diff options
author | Brad King <brad.king@kitware.com> | 2015-08-12 19:43:52 (GMT) |
---|---|---|
committer | Brad King <brad.king@kitware.com> | 2015-08-12 19:43:52 (GMT) |
commit | 91e8d35ab8ec2d62478a42eff10af88713497fad (patch) | |
tree | ff8cd1bd1ce3c42ef56c76b5ab471831a80c4665 /Utilities/cmcurl | |
parent | 602cdc06a01b7c5c0eb444111382b09040f677ee (diff) | |
parent | 706542615828488a5ad197d0ef3dd5e42eb739c4 (diff) | |
download | CMake-91e8d35ab8ec2d62478a42eff10af88713497fad.zip CMake-91e8d35ab8ec2d62478a42eff10af88713497fad.tar.gz CMake-91e8d35ab8ec2d62478a42eff10af88713497fad.tar.bz2 |
Merge branch 'curl-upstream' into update-curl
Resolve conflicts by taking upstream side when possible and otherwise
integrating the changes from both sides. Be carful in CMakeLists.txt
where the OPENSSL code block that we modified previously has moved, and
preserve our previous modifications in the new location.
Diffstat (limited to 'Utilities/cmcurl')
181 files changed, 14815 insertions, 11416 deletions
diff --git a/Utilities/cmcurl/CMake/CurlCheckCSourceCompiles.cmake b/Utilities/cmcurl/CMake/CurlCheckCSourceCompiles.cmake deleted file mode 100644 index 396001b..0000000 --- a/Utilities/cmcurl/CMake/CurlCheckCSourceCompiles.cmake +++ /dev/null @@ -1,71 +0,0 @@ -# - Check if the source code provided in the SOURCE argument compiles. -# CURL_CHECK_C_SOURCE_COMPILES(SOURCE VAR) -# - macro which checks if the source code compiles -# SOURCE - source code to try to compile -# VAR - variable to store whether the source code compiled -# -# The following variables may be set before calling this macro to -# modify the way the check is run: -# -# CMAKE_REQUIRED_FLAGS = string of compile command line flags -# CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar) -# CMAKE_REQUIRED_INCLUDES = list of include directories -# CMAKE_REQUIRED_LIBRARIES = list of libraries to link - -macro(CURL_CHECK_C_SOURCE_COMPILES SOURCE VAR) - if(NOT DEFINED "${VAR}") - set(message "${VAR}") - # If the number of arguments is greater than 2 (SOURCE VAR) - if(${ARGC} GREATER 2) - # then add the third argument as a message - set(message "${ARGV2} (${VAR})") - endif() - set(MACRO_CHECK_FUNCTION_DEFINITIONS - "-D${VAR} ${CMAKE_REQUIRED_FLAGS}") - if(CMAKE_REQUIRED_LIBRARIES) - set(CURL_CHECK_C_SOURCE_COMPILES_ADD_LIBRARIES - "-DLINK_LIBRARIES:STRING=${CMAKE_REQUIRED_LIBRARIES}") - endif() - if(CMAKE_REQUIRED_INCLUDES) - set(CURL_CHECK_C_SOURCE_COMPILES_ADD_INCLUDES - "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}") - endif() - set(src "") - foreach(def ${EXTRA_DEFINES}) - set(src "${src}#define ${def} 1\n") - endforeach(def) - foreach(inc ${HEADER_INCLUDES}) - set(src "${src}#include <${inc}>\n") - endforeach(inc) - - set(src "${src}\nint main() { ${SOURCE} ; return 0; }") - set(CMAKE_CONFIGURABLE_FILE_CONTENT "${src}") - configure_file(${CMAKE_CURRENT_SOURCE_DIR}/CMake/CMakeConfigurableFile.in - "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.c" - IMMEDIATE) - message(STATUS "Performing Test ${message}") - try_compile(${VAR} - ${CMAKE_BINARY_DIR} - ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.c - COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} - CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS} - "${CURL_CHECK_C_SOURCE_COMPILES_ADD_LIBRARIES}" - "${CURL_CHECK_C_SOURCE_COMPILES_ADD_INCLUDES}" - OUTPUT_VARIABLE OUTPUT) - if(${VAR}) - set(${VAR} 1 CACHE INTERNAL "Test ${message}") - message(STATUS "Performing Test ${message} - Success") - file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log - "Performing C SOURCE FILE Test ${message} succeded with the following output:\n" - "${OUTPUT}\n" - "Source file was:\n${src}\n") - else() - message(STATUS "Performing Test ${message} - Failed") - set(${VAR} "" CACHE INTERNAL "Test ${message}") - file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log - "Performing C SOURCE FILE Test ${message} failed with the following output:\n" - "${OUTPUT}\n" - "Source file was:\n${src}\n") - endif() - endif() -endmacro() diff --git a/Utilities/cmcurl/CMake/CurlCheckCSourceRuns.cmake b/Utilities/cmcurl/CMake/CurlCheckCSourceRuns.cmake deleted file mode 100644 index e62eebe..0000000 --- a/Utilities/cmcurl/CMake/CurlCheckCSourceRuns.cmake +++ /dev/null @@ -1,83 +0,0 @@ -# - Check if the source code provided in the SOURCE argument compiles and runs. -# CURL_CHECK_C_SOURCE_RUNS(SOURCE VAR) -# - macro which checks if the source code runs -# SOURCE - source code to try to compile -# VAR - variable to store size if the type exists. -# -# The following variables may be set before calling this macro to -# modify the way the check is run: -# -# CMAKE_REQUIRED_FLAGS = string of compile command line flags -# CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar) -# CMAKE_REQUIRED_INCLUDES = list of include directories -# CMAKE_REQUIRED_LIBRARIES = list of libraries to link - -macro(CURL_CHECK_C_SOURCE_RUNS SOURCE VAR) - if(NOT DEFINED "${VAR}") - set(message "${VAR}") - # If the number of arguments is greater than 2 (SOURCE VAR) - if(${ARGC} GREATER 2) - # then add the third argument as a message - set(message "${ARGV2} (${VAR})") - endif(${ARGC} GREATER 2) - set(MACRO_CHECK_FUNCTION_DEFINITIONS - "-D${VAR} ${CMAKE_REQUIRED_FLAGS}") - if(CMAKE_REQUIRED_LIBRARIES) - set(CURL_CHECK_C_SOURCE_COMPILES_ADD_LIBRARIES - "-DLINK_LIBRARIES:STRING=${CMAKE_REQUIRED_LIBRARIES}") - else(CMAKE_REQUIRED_LIBRARIES) - set(CURL_CHECK_C_SOURCE_COMPILES_ADD_LIBRARIES) - endif(CMAKE_REQUIRED_LIBRARIES) - if(CMAKE_REQUIRED_INCLUDES) - set(CURL_CHECK_C_SOURCE_COMPILES_ADD_INCLUDES - "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}") - else(CMAKE_REQUIRED_INCLUDES) - set(CURL_CHECK_C_SOURCE_COMPILES_ADD_INCLUDES) - endif(CMAKE_REQUIRED_INCLUDES) - set(src "") - foreach(def ${EXTRA_DEFINES}) - set(src "${src}#define ${def} 1\n") - endforeach(def) - foreach(inc ${HEADER_INCLUDES}) - set(src "${src}#include <${inc}>\n") - endforeach(inc) - - set(src "${src}\nint main() { ${SOURCE} ; return 0; }") - set(CMAKE_CONFIGURABLE_FILE_CONTENT "${src}") - configure_file(${CMAKE_CURRENT_SOURCE_DIR}/CMake/CMakeConfigurableFile.in - "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.c" - IMMEDIATE) - message(STATUS "Performing Test ${message}") - try_run(${VAR} ${VAR}_COMPILED - ${CMAKE_BINARY_DIR} - ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.c - COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} - CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS} - "${CURL_CHECK_C_SOURCE_COMPILES_ADD_LIBRARIES}" - "${CURL_CHECK_C_SOURCE_COMPILES_ADD_INCLUDES}" - OUTPUT_VARIABLE OUTPUT) - # if it did not compile make the return value fail code of 1 - if(NOT ${VAR}_COMPILED) - set(${VAR} 1) - endif(NOT ${VAR}_COMPILED) - # if the return value was 0 then it worked - set(result_var ${${VAR}}) - if("${result_var}" EQUAL 0) - set(${VAR} 1 CACHE INTERNAL "Test ${message}") - message(STATUS "Performing Test ${message} - Success") - file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log - "Performing C SOURCE FILE Test ${message} succeded with the following output:\n" - "${OUTPUT}\n" - "Return value: ${${VAR}}\n" - "Source file was:\n${src}\n") - else("${result_var}" EQUAL 0) - message(STATUS "Performing Test ${message} - Failed") - set(${VAR} "" CACHE INTERNAL "Test ${message}") - file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log - "Performing C SOURCE FILE Test ${message} failed with the following output:\n" - "${OUTPUT}\n" - "Return value: ${result_var}\n" - "Source file was:\n${src}\n") - endif("${result_var}" EQUAL 0) - endif() -endmacro(CURL_CHECK_C_SOURCE_RUNS) diff --git a/Utilities/cmcurl/CMake/CurlTests.c b/Utilities/cmcurl/CMake/CurlTests.c index 199871a..04d5e7e 100644 --- a/Utilities/cmcurl/CMake/CurlTests.c +++ b/Utilities/cmcurl/CMake/CurlTests.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -71,264 +71,88 @@ main () } #endif -#ifdef HAVE_GETHOSTBYADDR_R_5 +/* tests for gethostbyaddr_r or gethostbyname_r */ +#if defined(HAVE_GETHOSTBYADDR_R_5_REENTRANT) || \ + defined(HAVE_GETHOSTBYADDR_R_7_REENTRANT) || \ + defined(HAVE_GETHOSTBYADDR_R_8_REENTRANT) || \ + defined(HAVE_GETHOSTBYNAME_R_3_REENTRANT) || \ + defined(HAVE_GETHOSTBYNAME_R_5_REENTRANT) || \ + defined(HAVE_GETHOSTBYNAME_R_6_REENTRANT) +# define _REENTRANT + /* no idea whether _REENTRANT is always set, just invent a new flag */ +# define TEST_GETHOSTBYFOO_REENTRANT +#endif +#if defined(HAVE_GETHOSTBYADDR_R_5) || \ + defined(HAVE_GETHOSTBYADDR_R_7) || \ + defined(HAVE_GETHOSTBYADDR_R_8) || \ + defined(HAVE_GETHOSTBYNAME_R_3) || \ + defined(HAVE_GETHOSTBYNAME_R_5) || \ + defined(HAVE_GETHOSTBYNAME_R_6) || \ + defined(TEST_GETHOSTBYFOO_REENTRANT) #include <sys/types.h> #include <netdb.h> -int -main () -{ - -char * address; -int length; -int type; -struct hostent h; -struct hostent_data hdata; -int rc; -#ifndef gethostbyaddr_r - (void)gethostbyaddr_r; -#endif -rc = gethostbyaddr_r(address, length, type, &h, &hdata); - ; - return 0; -} -#endif -#ifdef HAVE_GETHOSTBYADDR_R_5_REENTRANT -#define _REENTRANT -#include <sys/types.h> -#include <netdb.h> -int -main () -{ - -char * address; -int length;q -int type; -struct hostent h; -struct hostent_data hdata; -int rc; -#ifndef gethostbyaddr_r - (void)gethostbyaddr_r; -#endif -rc = gethostbyaddr_r(address, length, type, &h, &hdata); - ; - return 0; -} -#endif -#ifdef HAVE_GETHOSTBYADDR_R_7 -#include <sys/types.h> -#include <netdb.h> -int -main () -{ - -char * address; -int length; -int type; -struct hostent h; -char buffer[8192]; -int h_errnop; -struct hostent * hp; - -#ifndef gethostbyaddr_r - (void)gethostbyaddr_r; -#endif -hp = gethostbyaddr_r(address, length, type, &h, - buffer, 8192, &h_errnop); - ; - return 0; -} -#endif -#ifdef HAVE_GETHOSTBYADDR_R_7_REENTRANT -#define _REENTRANT -#include <sys/types.h> -#include <netdb.h> -int -main () +int main(void) { - -char * address; -int length; -int type; -struct hostent h; -char buffer[8192]; -int h_errnop; -struct hostent * hp; - -#ifndef gethostbyaddr_r - (void)gethostbyaddr_r; -#endif -hp = gethostbyaddr_r(address, length, type, &h, - buffer, 8192, &h_errnop); - ; - return 0; -} + char *address = "example.com"; + int length = 0; + int type = 0; + struct hostent h; + int rc = 0; +#if defined(HAVE_GETHOSTBYADDR_R_5) || \ + defined(HAVE_GETHOSTBYADDR_R_5_REENTRANT) || \ + \ + defined(HAVE_GETHOSTBYNAME_R_3) || \ + defined(HAVE_GETHOSTBYNAME_R_3_REENTRANT) + struct hostent_data hdata; +#elif defined(HAVE_GETHOSTBYADDR_R_7) || \ + defined(HAVE_GETHOSTBYADDR_R_7_REENTRANT) || \ + defined(HAVE_GETHOSTBYADDR_R_8) || \ + defined(HAVE_GETHOSTBYADDR_R_8_REENTRANT) || \ + \ + defined(HAVE_GETHOSTBYNAME_R_5) || \ + defined(HAVE_GETHOSTBYNAME_R_5_REENTRANT) || \ + defined(HAVE_GETHOSTBYNAME_R_6) || \ + defined(HAVE_GETHOSTBYNAME_R_6_REENTRANT) + char buffer[8192]; + int h_errnop; + struct hostent *hp; #endif -#ifdef HAVE_GETHOSTBYADDR_R_8 -#include <sys/types.h> -#include <netdb.h> -int -main () -{ - -char * address; -int length; -int type; -struct hostent h; -char buffer[8192]; -int h_errnop; -struct hostent * hp; -int rc; - -#ifndef gethostbyaddr_r - (void)gethostbyaddr_r; -#endif -rc = gethostbyaddr_r(address, length, type, &h, - buffer, 8192, &hp, &h_errnop); - ; - return 0; -} -#endif -#ifdef HAVE_GETHOSTBYADDR_R_8_REENTRANT -#define _REENTRANT -#include <sys/types.h> -#include <netdb.h> -int -main () -{ - -char * address; -int length; -int type; -struct hostent h; -char buffer[8192]; -int h_errnop; -struct hostent * hp; -int rc; #ifndef gethostbyaddr_r (void)gethostbyaddr_r; #endif -rc = gethostbyaddr_r(address, length, type, &h, - buffer, 8192, &hp, &h_errnop); - ; - return 0; -} -#endif -#ifdef HAVE_GETHOSTBYNAME_R_3 -#include <string.h> -#include <sys/types.h> -#include <netdb.h> -#undef NULL -#define NULL (void *)0 - -int -main () -{ - -struct hostent_data data; -#ifndef gethostbyname_r - (void)gethostbyname_r; -#endif -gethostbyname_r(NULL, NULL, NULL); - ; - return 0; -} -#endif -#ifdef HAVE_GETHOSTBYNAME_R_3_REENTRANT -#define _REENTRANT -#include <string.h> -#include <sys/types.h> -#include <netdb.h> -#undef NULL -#define NULL (void *)0 - -int -main () -{ - -struct hostent_data data; -#ifndef gethostbyname_r - (void)gethostbyname_r; -#endif -gethostbyname_r(NULL, NULL, NULL); - ; - return 0; -} -#endif -#ifdef HAVE_GETHOSTBYNAME_R_5 -#include <sys/types.h> -#include <netinet/in.h> -#include <netdb.h> -#undef NULL -#define NULL (void *)0 - -int -main () -{ -#ifndef gethostbyname_r - (void)gethostbyname_r; -#endif -gethostbyname_r(NULL, NULL, NULL, 0, NULL); - ; - return 0; -} -#endif -#ifdef HAVE_GETHOSTBYNAME_R_5_REENTRANT -#define _REENTRANT -#include <sys/types.h> -#include <netdb.h> -#undef NULL -#define NULL (void *)0 -int -main () -{ - -#ifndef gethostbyname_r - (void)gethostbyname_r; -#endif -gethostbyname_r(NULL, NULL, NULL, 0, NULL); - ; +#if defined(HAVE_GETHOSTBYADDR_R_5) || \ + defined(HAVE_GETHOSTBYADDR_R_5_REENTRANT) + rc = gethostbyaddr_r(address, length, type, &h, &hdata); +#elif defined(HAVE_GETHOSTBYADDR_R_7) || \ + defined(HAVE_GETHOSTBYADDR_R_7_REENTRANT) + hp = gethostbyaddr_r(address, length, type, &h, buffer, 8192, &h_errnop); + (void)hp; +#elif defined(HAVE_GETHOSTBYADDR_R_8) || \ + defined(HAVE_GETHOSTBYADDR_R_8_REENTRANT) + rc = gethostbyaddr_r(address, length, type, &h, buffer, 8192, &hp, &h_errnop); +#endif + +#if defined(HAVE_GETHOSTBYNAME_R_3) || \ + defined(HAVE_GETHOSTBYNAME_R_3_REENTRANT) + rc = gethostbyname_r(address, &h, &hdata); +#elif defined(HAVE_GETHOSTBYNAME_R_5) || \ + defined(HAVE_GETHOSTBYNAME_R_5_REENTRANT) + rc = gethostbyname_r(address, &h, buffer, 8192, 0, &h_errnop); + (void)hp; /* not used for test */ +#elif defined(HAVE_GETHOSTBYNAME_R_6) || \ + defined(HAVE_GETHOSTBYNAME_R_6_REENTRANT) + rc = gethostbyname_r(address, &h, buffer, 8192, &hp, &h_errnop); +#endif + + (void)length; + (void)type; + (void)rc; return 0; } #endif -#ifdef HAVE_GETHOSTBYNAME_R_6 -#include <sys/types.h> -#include <netdb.h> -#undef NULL -#define NULL (void *)0 - -int -main () -{ -#ifndef gethostbyname_r - (void)gethostbyname_r; -#endif -gethostbyname_r(NULL, NULL, NULL, 0, NULL, NULL); - ; - return 0; -} -#endif -#ifdef HAVE_GETHOSTBYNAME_R_6_REENTRANT -#define _REENTRANT -#include <sys/types.h> -#include <netdb.h> -#undef NULL -#define NULL (void *)0 - -int -main () -{ - -#ifndef gethostbyname_r - (void)gethostbyname_r; -#endif -gethostbyname_r(NULL, NULL, NULL, 0, NULL, NULL); - ; - return 0; -} -#endif #ifdef HAVE_SOCKLEN_T #ifdef _WIN32 #include <ws2tcpip.h> diff --git a/Utilities/cmcurl/CMake/FindGSS.cmake b/Utilities/cmcurl/CMake/FindGSS.cmake new file mode 100644 index 0000000..dfaeaf3 --- /dev/null +++ b/Utilities/cmcurl/CMake/FindGSS.cmake @@ -0,0 +1,289 @@ +# - Try to find the GSS Kerberos library +# Once done this will define +# +# GSS_ROOT_DIR - Set this variable to the root installation of GSS +# +# Read-Only variables: +# GSS_FOUND - system has the Heimdal library +# GSS_FLAVOUR - "MIT" or "Heimdal" if anything found. +# GSS_INCLUDE_DIR - the Heimdal include directory +# GSS_LIBRARIES - The libraries needed to use GSS +# GSS_LINK_DIRECTORIES - Directories to add to linker search path +# GSS_LINKER_FLAGS - Additional linker flags +# GSS_COMPILER_FLAGS - Additional compiler flags +# GSS_VERSION - This is set to version advertised by pkg-config or read from manifest. +# In case the library is found but no version info availabe it'll be set to "unknown" + +set(_MIT_MODNAME mit-krb5-gssapi) +set(_HEIMDAL_MODNAME heimdal-gssapi) + +include(CheckIncludeFile) +include(CheckIncludeFiles) +include(CheckTypeSize) + +set(_GSS_ROOT_HINTS + "${GSS_ROOT_DIR}" + "$ENV{GSS_ROOT_DIR}" +) + +# try to find library using system pkg-config if user didn't specify root dir +if(NOT GSS_ROOT_DIR AND NOT "$ENV{GSS_ROOT_DIR}") + if(UNIX) + find_package(PkgConfig QUIET) + pkg_search_module(_GSS_PKG ${_MIT_MODNAME} ${_HEIMDAL_MODNAME}) + list(APPEND _GSS_ROOT_HINTS "${_GSS_PKG_PREFIX}") + elseif(WIN32) + list(APPEND _GSS_ROOT_HINTS "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MIT\\Kerberos;InstallDir]") + endif() +endif() + +if(NOT _GSS_FOUND) #not found by pkg-config. Let's take more traditional approach. + find_file(_GSS_CONFIGURE_SCRIPT + NAMES + "krb5-config" + HINTS + ${_GSS_ROOT_HINTS} + PATH_SUFFIXES + bin + NO_CMAKE_PATH + NO_CMAKE_ENVIRONMENT_PATH + ) + + # if not found in user-supplied directories, maybe system knows better + find_file(_GSS_CONFIGURE_SCRIPT + NAMES + "krb5-config" + PATH_SUFFIXES + bin + ) + + if(_GSS_CONFIGURE_SCRIPT) + execute_process( + COMMAND ${_GSS_CONFIGURE_SCRIPT} "--cflags" "gssapi" + OUTPUT_VARIABLE _GSS_CFLAGS + RESULT_VARIABLE _GSS_CONFIGURE_FAILED + ) +message(STATUS "CFLAGS: ${_GSS_CFLAGS}") + if(NOT _GSS_CONFIGURE_FAILED) # 0 means success + # should also work in an odd case when multiple directories are given + string(STRIP "${_GSS_CFLAGS}" _GSS_CFLAGS) + string(REGEX REPLACE " +-I" ";" _GSS_CFLAGS "${_GSS_CFLAGS}") + string(REGEX REPLACE " +-([^I][^ \\t;]*)" ";-\\1"_GSS_CFLAGS "${_GSS_CFLAGS}") + + foreach(_flag ${_GSS_CFLAGS}) + if(_flag MATCHES "^-I.*") + string(REGEX REPLACE "^-I" "" _val "${_flag}") + list(APPEND _GSS_INCLUDE_DIR "${_val}") + else() + list(APPEND _GSS_COMPILER_FLAGS "${_flag}") + endif() + endforeach() + endif() + + execute_process( + COMMAND ${_GSS_CONFIGURE_SCRIPT} "--libs" "gssapi" + OUTPUT_VARIABLE _GSS_LIB_FLAGS + RESULT_VARIABLE _GSS_CONFIGURE_FAILED + ) +message(STATUS "LDFLAGS: ${_GSS_LIB_FLAGS}") + if(NOT _GSS_CONFIGURE_FAILED) # 0 means success + # this script gives us libraries and link directories. Blah. We have to deal with it. + string(STRIP "${_GSS_LIB_FLAGS}" _GSS_LIB_FLAGS) + string(REGEX REPLACE " +-(L|l)" ";-\\1" _GSS_LIB_FLAGS "${_GSS_LIB_FLAGS}") + string(REGEX REPLACE " +-([^Ll][^ \\t;]*)" ";-\\1"_GSS_LIB_FLAGS "${_GSS_LIB_FLAGS}") + + foreach(_flag ${_GSS_LIB_FLAGS}) + if(_flag MATCHES "^-l.*") + string(REGEX REPLACE "^-l" "" _val "${_flag}") + list(APPEND _GSS_LIBRARIES "${_val}") + elseif(_flag MATCHES "^-L.*") + string(REGEX REPLACE "^-L" "" _val "${_flag}") + list(APPEND _GSS_LINK_DIRECTORIES "${_val}") + else() + list(APPEND _GSS_LINKER_FLAGS "${_flag}") + endif() + endforeach() + endif() + + + execute_process( + COMMAND ${_GSS_CONFIGURE_SCRIPT} "--version" + OUTPUT_VARIABLE _GSS_VERSION + RESULT_VARIABLE _GSS_CONFIGURE_FAILED + ) + + # older versions may not have the "--version" parameter. In this case we just don't care. + if(_GSS_CONFIGURE_FAILED) + set(_GSS_VERSION 0) + endif() + + + execute_process( + COMMAND ${_GSS_CONFIGURE_SCRIPT} "--vendor" + OUTPUT_VARIABLE _GSS_VENDOR + RESULT_VARIABLE _GSS_CONFIGURE_FAILED + ) + + # older versions may not have the "--vendor" parameter. In this case we just don't care. + if(_GSS_CONFIGURE_FAILED) + set(GSS_FLAVOUR "Heimdal") # most probably, shouldn't really matter + else() + if(_GSS_VENDOR MATCHES ".*H|heimdal.*") + set(GSS_FLAVOUR "Heimdal") + else() + set(GSS_FLAVOUR "MIT") + endif() + endif() + + else() # either there is no config script or we are on platform that doesn't provide one (Windows?) + + find_path(_GSS_INCLUDE_DIR + NAMES + "gssapi/gssapi.h" + HINTS + ${_GSS_ROOT_HINTS} + PATH_SUFFIXES + include + inc + ) + + if(_GSS_INCLUDE_DIR) #jay, we've found something + set(CMAKE_REQUIRED_INCLUDES "${_GSS_INCLUDE_DIR}") + check_include_files( "gssapi/gssapi_generic.h;gssapi/gssapi_krb5.h" _GSS_HAVE_MIT_HEADERS) + + if(_GSS_HAVE_MIT_HEADERS) + set(GSS_FLAVOUR "MIT") + else() + # prevent compiling the header - just check if we can include it + set(CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS} -D__ROKEN_H__") + check_include_file( "roken.h" _GSS_HAVE_ROKEN_H) + + check_include_file( "heimdal/roken.h" _GSS_HAVE_HEIMDAL_ROKEN_H) + if(_GSS_HAVE_ROKEN_H OR _GSS_HAVE_HEIMDAL_ROKEN_H) + set(GSS_FLAVOUR "Heimdal") + endif() + set(CMAKE_REQUIRED_DEFINITIONS "") + endif() + else() + # I'm not convienced if this is the right way but this is what autotools do at the moment + find_path(_GSS_INCLUDE_DIR + NAMES + "gssapi.h" + HINTS + ${_GSS_ROOT_HINTS} + PATH_SUFFIXES + include + inc + ) + + if(_GSS_INCLUDE_DIR) + set(GSS_FLAVOUR "Heimdal") + endif() + endif() + + # if we have headers, check if we can link libraries + if(GSS_FLAVOUR) + set(_GSS_LIBDIR_SUFFIXES "") + set(_GSS_LIBDIR_HINTS ${_GSS_ROOT_HINTS}) + get_filename_component(_GSS_CALCULATED_POTENTIAL_ROOT "${_GSS_INCLUDE_DIR}" PATH) + list(APPEND _GSS_LIBDIR_HINTS ${_GSS_CALCULATED_POTENTIAL_ROOT}) + + if(WIN32) + if(CMAKE_SIZEOF_VOID_P EQUAL 8) + list(APPEND _GSS_LIBDIR_SUFFIXES "lib/AMD64") + if(GSS_FLAVOUR STREQUAL "MIT") + set(_GSS_LIBNAME "gssapi64") + else() + set(_GSS_LIBNAME "libgssapi") + endif() + else() + list(APPEND _GSS_LIBDIR_SUFFIXES "lib/i386") + if(GSS_FLAVOUR STREQUAL "MIT") + set(_GSS_LIBNAME "gssapi32") + else() + set(_GSS_LIBNAME "libgssapi") + endif() + endif() + else() + list(APPEND _GSS_LIBDIR_SUFFIXES "lib;lib64") # those suffixes are not checked for HINTS + if(GSS_FLAVOUR STREQUAL "MIT") + set(_GSS_LIBNAME "gssapi_krb5") + else() + set(_GSS_LIBNAME "gssapi") + endif() + endif() + + find_library(_GSS_LIBRARIES + NAMES + ${_GSS_LIBNAME} + HINTS + ${_GSS_LIBDIR_HINTS} + PATH_SUFFIXES + ${_GSS_LIBDIR_SUFFIXES} + ) + + endif() + + endif() +else() + if(_GSS_PKG_${_MIT_MODNAME}_VERSION) + set(GSS_FLAVOUR "MIT") + set(_GSS_VERSION _GSS_PKG_${_MIT_MODNAME}_VERSION) + else() + set(GSS_FLAVOUR "Heimdal") + set(_GSS_VERSION _GSS_PKG_${_MIT_HEIMDAL}_VERSION) + endif() +endif() + +set(GSS_INCLUDE_DIR ${_GSS_INCLUDE_DIR}) +set(GSS_LIBRARIES ${_GSS_LIBRARIES}) +set(GSS_LINK_DIRECTORIES ${_GSS_LINK_DIRECTORIES}) +set(GSS_LINKER_FLAGS ${_GSS_LINKER_FLAGS}) +set(GSS_COMPILER_FLAGS ${_GSS_COMPILER_FLAGS}) +set(GSS_VERSION ${_GSS_VERSION}) + +if(GSS_FLAVOUR) + + if(NOT GSS_VERSION AND GSS_FLAVOUR STREQUAL "Heimdal") + if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(HEIMDAL_MANIFEST_FILE "Heimdal.Application.amd64.manifest") + else() + set(HEIMDAL_MANIFEST_FILE "Heimdal.Application.x86.manifest") + endif() + + if(EXISTS "${GSS_INCLUDE_DIR}/${HEIMDAL_MANIFEST_FILE}") + file(STRINGS "${GSS_INCLUDE_DIR}/${HEIMDAL_MANIFEST_FILE}" heimdal_version_str + REGEX "^.*version=\"[0-9]\\.[^\"]+\".*$") + + string(REGEX MATCH "[0-9]\\.[^\"]+" + GSS_VERSION "${heimdal_version_str}") + endif() + + if(NOT GSS_VERSION) + set(GSS_VERSION "Heimdal Unknown") + endif() + elseif(NOT GSS_VERSION AND GSS_FLAVOUR STREQUAL "MIT") + get_filename_component(_MIT_VERSION "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MIT\\Kerberos\\SDK\\CurrentVersion;VersionString]" NAME CACHE) + if(WIN32 AND _MIT_VERSION) + set(GSS_VERSION "${_MIT_VERSION}") + else() + set(GSS_VERSION "MIT Unknown") + endif() + endif() +endif() + + +include(FindPackageHandleStandardArgs) + +set(_GSS_REQUIRED_VARS GSS_LIBRARIES GSS_FLAVOUR) + +find_package_handle_standard_args(GSS + REQUIRED_VARS + ${_GSS_REQUIRED_VARS} + VERSION_VAR + GSS_VERSION + FAIL_MESSAGE + "Could NOT find GSS, try to set the path to GSS root folder in the system variable GSS_ROOT_DIR" +) + +mark_as_advanced(GSS_INCLUDE_DIR GSS_LIBRARIES) diff --git a/Utilities/cmcurl/CMake/Macros.cmake b/Utilities/cmcurl/CMake/Macros.cmake index 0f8eb57..dab005f 100644 --- a/Utilities/cmcurl/CMake/Macros.cmake +++ b/Utilities/cmcurl/CMake/Macros.cmake @@ -1,7 +1,10 @@ #File defines convenience macros for available feature testing # This macro checks if the symbol exists in the library and if it -# does, it prepends library to the list. +# does, it prepends library to the list. It is intended to be called +# multiple times with a sequence of possibly dependent libraries in +# order of least-to-most-dependent. Some libraries depend on others +# to link correctly. macro(CHECK_LIBRARY_EXISTS_CONCAT LIBRARY SYMBOL VARIABLE) check_library_exists("${LIBRARY};${CURL_LIBS}" ${SYMBOL} "${CMAKE_LIBRARY_PATH}" ${VARIABLE}) @@ -11,6 +14,9 @@ macro(CHECK_LIBRARY_EXISTS_CONCAT LIBRARY SYMBOL VARIABLE) endmacro(CHECK_LIBRARY_EXISTS_CONCAT) # Check if header file exists and add it to the list. +# This macro is intended to be called multiple times with a sequence of +# possibly dependent header files. Some headers depend on others to be +# compiled correctly. macro(CHECK_INCLUDE_FILE_CONCAT FILE VARIABLE) check_include_files("${CURL_INCLUDES};${FILE}" ${VARIABLE}) if(${VARIABLE}) diff --git a/Utilities/cmcurl/CMake/OtherTests.cmake b/Utilities/cmcurl/CMake/OtherTests.cmake index 039d189..4f07f22 100644 --- a/Utilities/cmcurl/CMake/OtherTests.cmake +++ b/Utilities/cmcurl/CMake/OtherTests.cmake @@ -1,15 +1,10 @@ -include(CurlCheckCSourceCompiles) -set(EXTRA_DEFINES "__unused1\n#undef inline\n#define __unused2") -set(HEADER_INCLUDES) -set(headers_hack) +include(CheckCSourceCompiles) +# The begin of the sources (macros and includes) +set(_source_epilogue "#undef inline") macro(add_header_include check header) if(${check}) - set(headers_hack - "${headers_hack}\n#include <${header}>") - #SET(HEADER_INCLUDES - # ${HEADER_INCLUDES} - # "${header}") + set(_source_epilogue "${_source_epilogue}\n#include <${header}>") endif(${check}) endmacro(add_header_include) @@ -18,8 +13,8 @@ if(HAVE_WINDOWS_H) add_header_include(HAVE_WINDOWS_H "windows.h") add_header_include(HAVE_WINSOCK2_H "winsock2.h") add_header_include(HAVE_WINSOCK_H "winsock.h") - set(EXTRA_DEFINES ${EXTRA_DEFINES} - "__unused7\n#ifndef WIN32_LEAN_AND_MEAN\n#define WIN32_LEAN_AND_MEAN\n#endif\n#define __unused3") + set(_source_epilogue + "${_source_epilogue}\n#ifndef WIN32_LEAN_AND_MEAN\n#define WIN32_LEAN_AND_MEAN\n#endif") set(signature_call_conv "PASCAL") if(HAVE_LIBWS2_32) set(CMAKE_REQUIRED_LIBRARIES ws2_32) @@ -29,14 +24,12 @@ else(HAVE_WINDOWS_H) add_header_include(HAVE_SYS_SOCKET_H "sys/socket.h") endif(HAVE_WINDOWS_H) -set(EXTRA_DEFINES_BACKUP "${EXTRA_DEFINES}") -set(EXTRA_DEFINES "${EXTRA_DEFINES_BACKUP}\n${headers_hack}\n${extern_line}\n#define __unused5") -curl_check_c_source_compiles("recv(0, 0, 0, 0)" curl_cv_recv) +check_c_source_compiles("${_source_epilogue} +int main(void) { + recv(0, 0, 0, 0); + return 0; +}" curl_cv_recv) if(curl_cv_recv) - # AC_CACHE_CHECK([types of arguments and return type for recv], - #[curl_cv_func_recv_args], [ - #SET(curl_cv_func_recv_args "unknown") - #for recv_retv in 'int' 'ssize_t'; do 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") @@ -45,16 +38,22 @@ if(curl_cv_recv) foreach(recv_arg4 "int" "unsigned int") if(NOT curl_cv_func_recv_done) unset(curl_cv_func_recv_test CACHE) - set(extern_line "extern ${recv_retv} ${signature_call_conv} recv(${recv_arg1}, ${recv_arg2}, ${recv_arg3}, ${recv_arg4})\;") - set(EXTRA_DEFINES "${EXTRA_DEFINES_BACKUP}\n${headers_hack}\n${extern_line}\n#define __unused5") - curl_check_c_source_compiles(" + check_c_source_compiles(" + ${_source_epilogue} + extern ${recv_retv} ${signature_call_conv} + recv(${recv_arg1}, ${recv_arg2}, ${recv_arg3}, ${recv_arg4}); + int main(void) { ${recv_arg1} s=0; ${recv_arg2} buf=0; ${recv_arg3} len=0; ${recv_arg4} flags=0; - ${recv_retv} res = recv(s, buf, len, flags)" - curl_cv_func_recv_test - "${recv_retv} recv(${recv_arg1}, ${recv_arg2}, ${recv_arg3}, ${recv_arg4})") + ${recv_retv} res = recv(s, buf, len, flags); + (void) res; + return 0; + }" + curl_cv_func_recv_test) + message(STATUS + "Tested: ${recv_retv} recv(${recv_arg1}, ${recv_arg2}, ${recv_arg3}, ${recv_arg4})") if(curl_cv_func_recv_test) set(curl_cv_func_recv_args "${recv_arg1},${recv_arg2},${recv_arg3},${recv_arg4},${recv_retv}") @@ -72,18 +71,13 @@ if(curl_cv_recv) endforeach(recv_arg2) endforeach(recv_arg1) endforeach(recv_retv) - else(NOT DEFINED curl_cv_func_recv_args OR "${curl_cv_func_recv_args}" STREQUAL "unknown") + else() string(REGEX REPLACE "^([^,]*),[^,]*,[^,]*,[^,]*,[^,]*$" "\\1" RECV_TYPE_ARG1 "${curl_cv_func_recv_args}") string(REGEX REPLACE "^[^,]*,([^,]*),[^,]*,[^,]*,[^,]*$" "\\1" RECV_TYPE_ARG2 "${curl_cv_func_recv_args}") string(REGEX REPLACE "^[^,]*,[^,]*,([^,]*),[^,]*,[^,]*$" "\\1" RECV_TYPE_ARG3 "${curl_cv_func_recv_args}") string(REGEX REPLACE "^[^,]*,[^,]*,[^,]*,([^,]*),[^,]*$" "\\1" RECV_TYPE_ARG4 "${curl_cv_func_recv_args}") string(REGEX REPLACE "^[^,]*,[^,]*,[^,]*,[^,]*,([^,]*)$" "\\1" RECV_TYPE_RETV "${curl_cv_func_recv_args}") - #MESSAGE("RECV_TYPE_ARG1 ${RECV_TYPE_ARG1}") - #MESSAGE("RECV_TYPE_ARG2 ${RECV_TYPE_ARG2}") - #MESSAGE("RECV_TYPE_ARG3 ${RECV_TYPE_ARG3}") - #MESSAGE("RECV_TYPE_ARG4 ${RECV_TYPE_ARG4}") - #MESSAGE("RECV_TYPE_RETV ${RECV_TYPE_RETV}") - endif(NOT DEFINED curl_cv_func_recv_args OR "${curl_cv_func_recv_args}" STREQUAL "unknown") + endif() if("${curl_cv_func_recv_args}" STREQUAL "unknown") message(FATAL_ERROR "Cannot find proper types to use for recv args") @@ -94,12 +88,12 @@ endif(curl_cv_recv) set(curl_cv_func_recv_args "${curl_cv_func_recv_args}" CACHE INTERNAL "Arguments for recv") set(HAVE_RECV 1) -curl_check_c_source_compiles("send(0, 0, 0, 0)" curl_cv_send) +check_c_source_compiles("${_source_epilogue} +int main(void) { + send(0, 0, 0, 0); + return 0; +}" curl_cv_send) if(curl_cv_send) - # AC_CACHE_CHECK([types of arguments and return type for send], - #[curl_cv_func_send_args], [ - #SET(curl_cv_func_send_args "unknown") - #for send_retv in 'int' 'ssize_t'; do 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") @@ -108,18 +102,23 @@ if(curl_cv_send) foreach(send_arg4 "int" "unsigned int") if(NOT curl_cv_func_send_done) unset(curl_cv_func_send_test CACHE) - set(extern_line "extern ${send_retv} ${signature_call_conv} send(${send_arg1}, ${send_arg2}, ${send_arg3}, ${send_arg4})\;") - set(EXTRA_DEFINES "${EXTRA_DEFINES_BACKUP}\n${headers_hack}\n${extern_line}\n#define __unused5") - curl_check_c_source_compiles(" + check_c_source_compiles(" + ${_source_epilogue} + extern ${send_retv} ${signature_call_conv} + send(${send_arg1}, ${send_arg2}, ${send_arg3}, ${send_arg4}); + int main(void) { ${send_arg1} s=0; ${send_arg2} buf=0; ${send_arg3} len=0; ${send_arg4} flags=0; - ${send_retv} res = send(s, buf, len, flags)" - curl_cv_func_send_test - "${send_retv} send(${send_arg1}, ${send_arg2}, ${send_arg3}, ${send_arg4})") + ${send_retv} res = send(s, buf, len, flags); + (void) res; + return 0; + }" + curl_cv_func_send_test) + message(STATUS + "Tested: ${send_retv} send(${send_arg1}, ${send_arg2}, ${send_arg3}, ${send_arg4})") if(curl_cv_func_send_test) - #MESSAGE("Found arguments: ${curl_cv_func_send_test}") string(REGEX REPLACE "(const) .*" "\\1" send_qual_arg2 "${send_arg2}") string(REGEX REPLACE "const (.*)" "\\1" send_arg2 "${send_arg2}") set(curl_cv_func_send_args @@ -138,20 +137,14 @@ if(curl_cv_send) endforeach(send_arg2) endforeach(send_arg1) endforeach(send_retv) - else(NOT DEFINED curl_cv_func_send_args OR "${curl_cv_func_send_args}" STREQUAL "unknown") + else() string(REGEX REPLACE "^([^,]*),[^,]*,[^,]*,[^,]*,[^,]*,[^,]*$" "\\1" SEND_TYPE_ARG1 "${curl_cv_func_send_args}") string(REGEX REPLACE "^[^,]*,([^,]*),[^,]*,[^,]*,[^,]*,[^,]*$" "\\1" SEND_TYPE_ARG2 "${curl_cv_func_send_args}") string(REGEX REPLACE "^[^,]*,[^,]*,([^,]*),[^,]*,[^,]*,[^,]*$" "\\1" SEND_TYPE_ARG3 "${curl_cv_func_send_args}") string(REGEX REPLACE "^[^,]*,[^,]*,[^,]*,([^,]*),[^,]*,[^,]*$" "\\1" SEND_TYPE_ARG4 "${curl_cv_func_send_args}") string(REGEX REPLACE "^[^,]*,[^,]*,[^,]*,[^,]*,([^,]*),[^,]*$" "\\1" SEND_TYPE_RETV "${curl_cv_func_send_args}") string(REGEX REPLACE "^[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,([^,]*)$" "\\1" SEND_QUAL_ARG2 "${curl_cv_func_send_args}") - #MESSAGE("SEND_TYPE_ARG1 ${SEND_TYPE_ARG1}") - #MESSAGE("SEND_TYPE_ARG2 ${SEND_TYPE_ARG2}") - #MESSAGE("SEND_TYPE_ARG3 ${SEND_TYPE_ARG3}") - #MESSAGE("SEND_TYPE_ARG4 ${SEND_TYPE_ARG4}") - #MESSAGE("SEND_TYPE_RETV ${SEND_TYPE_RETV}") - #MESSAGE("SEND_QUAL_ARG2 ${SEND_QUAL_ARG2}") - endif(NOT DEFINED curl_cv_func_send_args OR "${curl_cv_func_send_args}" STREQUAL "unknown") + endif() if("${curl_cv_func_send_args}" STREQUAL "unknown") message(FATAL_ERROR "Cannot find proper types to use for send args") @@ -163,88 +156,71 @@ endif(curl_cv_send) set(curl_cv_func_send_args "${curl_cv_func_send_args}" CACHE INTERNAL "Arguments for send") set(HAVE_SEND 1) -set(EXTRA_DEFINES "${EXTRA_DEFINES}\n${headers_hack}\n#define __unused5") -curl_check_c_source_compiles("int flag = MSG_NOSIGNAL" HAVE_MSG_NOSIGNAL) - -set(EXTRA_DEFINES "__unused1\n#undef inline\n#define __unused2") -set(HEADER_INCLUDES) -set(headers_hack) +check_c_source_compiles("${_source_epilogue} + int main(void) { + int flag = MSG_NOSIGNAL; + (void)flag; + return 0; + }" HAVE_MSG_NOSIGNAL) -macro(add_header_include check header) - if(${check}) - set(headers_hack - "${headers_hack}\n#include <${header}>") - #SET(HEADER_INCLUDES - # ${HEADER_INCLUDES} - # "${header}") - endif(${check}) -endmacro(add_header_include header) - -if(HAVE_WINDOWS_H) - set(EXTRA_DEFINES ${EXTRA_DEFINES} - "__unused7\n#ifndef WIN32_LEAN_AND_MEAN\n#define WIN32_LEAN_AND_MEAN\n#endif\n#define __unused3") - add_header_include(HAVE_WINDOWS_H "windows.h") - add_header_include(HAVE_WINSOCK2_H "winsock2.h") - add_header_include(HAVE_WINSOCK_H "winsock.h") -else(HAVE_WINDOWS_H) - add_header_include(HAVE_SYS_TYPES_H "sys/types.h") +if(NOT HAVE_WINDOWS_H) add_header_include(HAVE_SYS_TIME_H "sys/time.h") add_header_include(TIME_WITH_SYS_TIME "time.h") add_header_include(HAVE_TIME_H "time.h") -endif(HAVE_WINDOWS_H) -set(EXTRA_DEFINES "${EXTRA_DEFINES}\n${headers_hack}\n#define __unused5") -curl_check_c_source_compiles("struct timeval ts;\nts.tv_sec = 0;\nts.tv_usec = 0" HAVE_STRUCT_TIMEVAL) - - -include(CurlCheckCSourceRuns) -set(EXTRA_DEFINES) -set(HEADER_INCLUDES) +endif() +check_c_source_compiles("${_source_epilogue} +int main(void) { + struct timeval ts; + ts.tv_sec = 0; + ts.tv_usec = 0; + (void)ts; + return 0; +}" HAVE_STRUCT_TIMEVAL) + + +include(CheckCSourceRuns) +set(CMAKE_REQUIRED_FLAGS) if(HAVE_SYS_POLL_H) - set(HEADER_INCLUDES "sys/poll.h") + set(CMAKE_REQUIRED_FLAGS "-DHAVE_SYS_POLL_H") endif(HAVE_SYS_POLL_H) -curl_check_c_source_runs("return poll((void *)0, 0, 10 /*ms*/)" HAVE_POLL_FINE) +check_c_source_runs(" + #ifdef HAVE_SYS_POLL_H + # include <sys/poll.h> + #endif + int main(void) { + return poll((void *)0, 0, 10 /*ms*/); + }" HAVE_POLL_FINE) set(HAVE_SIG_ATOMIC_T 1) -set(EXTRA_DEFINES) -set(HEADER_INCLUDES) +set(CMAKE_REQUIRED_FLAGS) if(HAVE_SIGNAL_H) - set(HEADER_INCLUDES "signal.h") + set(CMAKE_REQUIRED_FLAGS "-DHAVE_SIGNAL_H") set(CMAKE_EXTRA_INCLUDE_FILES "signal.h") endif(HAVE_SIGNAL_H) check_type_size("sig_atomic_t" SIZEOF_SIG_ATOMIC_T) if(HAVE_SIZEOF_SIG_ATOMIC_T) - curl_check_c_source_compiles("static volatile sig_atomic_t dummy = 0" HAVE_SIG_ATOMIC_T_NOT_VOLATILE) + check_c_source_compiles(" + #ifdef HAVE_SIGNAL_H + # include <signal.h> + #endif + int main(void) { + static volatile sig_atomic_t dummy = 0; + (void)dummy; + return 0; + }" HAVE_SIG_ATOMIC_T_NOT_VOLATILE) if(NOT HAVE_SIG_ATOMIC_T_NOT_VOLATILE) set(HAVE_SIG_ATOMIC_T_VOLATILE 1) endif(NOT HAVE_SIG_ATOMIC_T_NOT_VOLATILE) endif(HAVE_SIZEOF_SIG_ATOMIC_T) -set(CHECK_TYPE_SIZE_PREINCLUDE - "#undef inline") - if(HAVE_WINDOWS_H) - set(CHECK_TYPE_SIZE_PREINCLUDE "${CHECK_TYPE_SIZE_PREINCLUDE} - #ifndef WIN32_LEAN_AND_MEAN - #define WIN32_LEAN_AND_MEAN - #endif - #include <windows.h>") - if(HAVE_WINSOCK2_H) - set(CHECK_TYPE_SIZE_PREINCLUDE "${CHECK_TYPE_SIZE_PREINCLUDE}\n#include <winsock2.h>") - endif(HAVE_WINSOCK2_H) -else(HAVE_WINDOWS_H) + set(CMAKE_EXTRA_INCLUDE_FILES winsock2.h) +else() + set(CMAKE_EXTRA_INCLUDE_FILES) if(HAVE_SYS_SOCKET_H) - set(CMAKE_EXTRA_INCLUDE_FILES ${CMAKE_EXTRA_INCLUDE_FILES} - "sys/socket.h") + set(CMAKE_EXTRA_INCLUDE_FILES sys/socket.h) endif(HAVE_SYS_SOCKET_H) - if(HAVE_NETINET_IN_H) - set(CMAKE_EXTRA_INCLUDE_FILES ${CMAKE_EXTRA_INCLUDE_FILES} - "netinet/in.h") - endif(HAVE_NETINET_IN_H) - if(HAVE_ARPA_INET_H) - set(CMAKE_EXTRA_INCLUDE_FILES ${CMAKE_EXTRA_INCLUDE_FILES} - "arpa/inet.h") - endif(HAVE_ARPA_INET_H) -endif(HAVE_WINDOWS_H) +endif() check_type_size("struct sockaddr_storage" SIZEOF_STRUCT_SOCKADDR_STORAGE) if(HAVE_SIZEOF_STRUCT_SOCKADDR_STORAGE) diff --git a/Utilities/cmcurl/CMake/Platforms/WindowsCache.cmake b/Utilities/cmcurl/CMake/Platforms/WindowsCache.cmake index 0e26a17..53d0a5e 100644 --- a/Utilities/cmcurl/CMake/Platforms/WindowsCache.cmake +++ b/Utilities/cmcurl/CMake/Platforms/WindowsCache.cmake @@ -5,6 +5,7 @@ if(NOT UNIX) set(HAVE_LIBSOCKET 0) set(NOT_NEED_LIBNSL 0) set(HAVE_LIBNSL 0) + set(HAVE_GETHOSTNAME 1) set(HAVE_LIBZ 0) set(HAVE_LIBCRYPTO 0) @@ -14,7 +15,6 @@ if(NOT UNIX) set(HAVE_ARPA_INET_H 0) set(HAVE_DLFCN_H 0) set(HAVE_FCNTL_H 1) - set(HAVE_FEATURES_H 0) set(HAVE_INTTYPES_H 0) set(HAVE_IO_H 1) set(HAVE_MALLOC_H 1) diff --git a/Utilities/cmcurl/CMakeLists.txt b/Utilities/cmcurl/CMakeLists.txt index 32e4561..6b01be9 100644 --- a/Utilities/cmcurl/CMakeLists.txt +++ b/Utilities/cmcurl/CMakeLists.txt @@ -51,7 +51,7 @@ endif() # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # -# Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. +# Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms @@ -96,27 +96,17 @@ message(WARNING "the curl cmake build system is poorly maintained. Be aware") endif() file (READ ${CURL_SOURCE_DIR}/include/curl/curlver.h CURL_VERSION_H_CONTENTS) -string (REGEX MATCH "LIBCURL_VERSION_MAJOR[ \t]+([0-9]+)" - LIBCURL_VERSION_MJ ${CURL_VERSION_H_CONTENTS}) -string (REGEX MATCH "([0-9]+)" - LIBCURL_VERSION_MJ ${LIBCURL_VERSION_MJ}) -string (REGEX MATCH - "LIBCURL_VERSION_MINOR[ \t]+([0-9]+)" - LIBCURL_VERSION_MI ${CURL_VERSION_H_CONTENTS}) -string (REGEX MATCH "([0-9]+)" LIBCURL_VERSION_MI ${LIBCURL_VERSION_MI}) -string (REGEX MATCH - "LIBCURL_VERSION_PATCH[ \t]+([0-9]+)" - LIBCURL_VERSION_PT ${CURL_VERSION_H_CONTENTS}) -string (REGEX MATCH "([0-9]+)" LIBCURL_VERSION_PT ${LIBCURL_VERSION_PT}) -set (CURL_MAJOR_VERSION ${LIBCURL_VERSION_MJ}) -set (CURL_MINOR_VERSION ${LIBCURL_VERSION_MI}) -set (CURL_PATCH_VERSION ${LIBCURL_VERSION_PT}) +string (REGEX MATCH "#define LIBCURL_VERSION \"[^\"]*" + CURL_VERSION ${CURL_VERSION_H_CONTENTS}) +string (REGEX REPLACE "[^\"]+\"" "" CURL_VERSION ${CURL_VERSION}) +string (REGEX MATCH "#define LIBCURL_VERSION_NUM 0x[0-9a-fA-F]+" + CURL_VERSION_NUM ${CURL_VERSION_H_CONTENTS}) +string (REGEX REPLACE "[^0]+0x" "" CURL_VERSION_NUM ${CURL_VERSION_NUM}) include_regular_expression("^.*$") # Sukender: Is it necessary? # Setup package meta-data # SET(PACKAGE "curl") -set(CURL_VERSION ${CURL_MAJOR_VERSION}.${CURL_MINOR_VERSION}.${CURL_PATCH_VERSION}) if(0) # This code not needed for building within CMake. message(STATUS "curl version=[${CURL_VERSION}]") endif() @@ -134,12 +124,35 @@ include_directories( ${CURL_SOURCE_DIR}/include ) option(BUILD_CURL_EXE "Set to ON to build cURL executable." ON) option(BUILD_CURL_TESTS "Set to ON to build cURL tests." ON) option(CURL_STATICLIB "Set to ON to build libcurl with static linking." OFF) -option(CURL_USE_ARES "Set to ON to enable c-ares support" OFF) +option(ENABLE_ARES "Set to ON to enable c-ares support" OFF) +option(ENABLE_THREADED_RESOLVER "Set to ON to enable POSIX threaded DNS lookup" 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 (ENABLE_DEBUG) + # DEBUGBUILD will be defined only for Debug builds + if(NOT CMAKE_VERSION VERSION_LESS 3.0) + set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS $<$<CONFIG:Debug>:DEBUGBUILD>) + else() + set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS_DEBUG DEBUGBUILD) + endif() + set(ENABLE_CURLDEBUG ON) +endif() + +if (ENABLE_CURLDEBUG) + set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS CURLDEBUG) +endif() + # initialize CURL_LIBS set(CURL_LIBS "") -if(CURL_USE_ARES) - set(USE_ARES ${CURL_USE_ARES}) +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) list(APPEND CURL_LIBS ${CARES_LIBRARY} ) set(CURL_LIBS ${CURL_LIBS} ${CARES_LIBRARY}) @@ -221,9 +234,52 @@ 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" OFF) +option(ENABLE_IPV6 "Define if you want to enable IPv6 support" ON) mark_as_advanced(ENABLE_IPV6) +if(ENABLE_IPV6) + include(CheckStructHasMember) + check_struct_has_member("struct sockaddr_in6" sin6_addr "netinet/in.h" + HAVE_SOCKADDR_IN6_SIN6_ADDR) + check_struct_has_member("struct sockaddr_in6" sin6_scope_id "netinet/in.h" + HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID) + if(NOT HAVE_SOCKADDR_IN6_SIN6_ADDR) + message(WARNING "struct sockaddr_in6 not available, disabling IPv6 support") + # Force the feature off as this name is used as guard macro... + set(ENABLE_IPV6 OFF + CACHE BOOL "Define if you want to enable IPv6 support" FORCE) + endif() +endif() +option(ENABLE_MANUAL "to provide the built-in manual" ON) +unset(USE_MANUAL CACHE) # TODO: cache NROFF/NROFF_MANOPT/USE_MANUAL vars? +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() +endif() # We need ansi c-flags, especially on HP set(CMAKE_C_FLAGS "${CMAKE_ANSI_CFLAGS} ${CMAKE_C_FLAGS}") @@ -250,9 +306,22 @@ include (CheckCSourceCompiles) # On windows preload settings if(WIN32) + set(CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS} -D_WINSOCKAPI_") include(${CMAKE_CURRENT_SOURCE_DIR}/CMake/Platforms/WindowsCache.cmake) endif(WIN32) +if(ENABLE_THREADED_RESOLVER) + 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() +endif() + # Check for all needed libraries if(0) # This code not needed for building within CMake. check_library_exists_concat("dl" dlopen HAVE_LIBDL) @@ -277,19 +346,78 @@ if(NOT NOT_NEED_LIBNSL) check_library_exists_concat("nsl" gethostbyname HAVE_LIBNSL) endif(NOT NOT_NEED_LIBNSL) +check_function_exists(gethostname HAVE_GETHOSTNAME) + if(WIN32) check_library_exists_concat("ws2_32" getch HAVE_LIBWS2_32) check_library_exists_concat("winmm" getch HAVE_LIBWINMM) endif() +set(USE_OPENSSL OFF) +set(HAVE_LIBCRYPTO OFF) +set(HAVE_LIBSSL OFF) + +if(CMAKE_USE_OPENSSL) + find_package(OpenSSL) + if(OPENSSL_FOUND) + list(APPEND CURL_LIBS ${OPENSSL_LIBRARIES}) + set(USE_OPENSSL ON) + set(HAVE_LIBCRYPTO ON) + set(HAVE_LIBSSL ON) + include_directories(${OPENSSL_INCLUDE_DIR}) + set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR}) + check_include_file("openssl/crypto.h" HAVE_OPENSSL_CRYPTO_H) + check_include_file("openssl/engine.h" HAVE_OPENSSL_ENGINE_H) + check_include_file("openssl/err.h" HAVE_OPENSSL_ERR_H) + check_include_file("openssl/pem.h" HAVE_OPENSSL_PEM_H) + check_include_file("openssl/pkcs12.h" HAVE_OPENSSL_PKCS12_H) + check_include_file("openssl/rsa.h" HAVE_OPENSSL_RSA_H) + check_include_file("openssl/ssl.h" HAVE_OPENSSL_SSL_H) + check_include_file("openssl/x509.h" HAVE_OPENSSL_X509_H) + check_include_file("openssl/rand.h" HAVE_OPENSSL_RAND_H) + + # Optionally build with a specific CA cert bundle. + if(CURL_CA_BUNDLE) + add_definitions(-DCURL_CA_BUNDLE="${CURL_CA_BUNDLE}") + endif() + # Optionally build with a specific CA cert dir. + if(CURL_CA_PATH) + add_definitions(-DCURL_CA_PATH="${CURL_CA_PATH}") + endif() + endif() +elseif(WIN32) + # Use Windows SSL/TLS native implementation. + add_definitions(-DUSE_SCHANNEL) + set(USE_WINDOWS_SSPI 1) +elseif(APPLE) + # Use OS X SSL/TLS native implementation if available on target version. + if(CMAKE_OSX_DEPLOYMENT_TARGET) + set(OSX_VERSION ${CMAKE_OSX_DEPLOYMENT_TARGET}) + else() + execute_process( + COMMAND sw_vers -productVersion + OUTPUT_VARIABLE OSX_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + endif() + if(NOT OSX_VERSION VERSION_LESS 10.6 AND + CMAKE_C_COMPILER_ID MATCHES "GNU|Clang|AppleClang") + add_definitions(-DUSE_DARWINSSL) + list(APPEND CURL_LIBS + "-framework CoreFoundation" + "-framework Security" + ) + endif() +endif() + if(NOT CURL_DISABLE_LDAP) if(WIN32) - option(CURL_LDAP_WIN "Use Windows LDAP implementation" ON) - if(CURL_LDAP_WIN) + option(USE_WIN32_LDAP "Use Windows LDAP implementation" ON) + if(USE_WIN32_LDAP) check_library_exists("wldap32" cldap_open "" HAVE_WLDAP32) if(NOT HAVE_WLDAP32) - set(CURL_LDAP_WIN OFF) + set(USE_WIN32_LDAP OFF) endif() endif() endif() @@ -299,13 +427,14 @@ if(NOT CURL_DISABLE_LDAP) set(CMAKE_LDAP_LIB "ldap" CACHE STRING "Name or full path to ldap library") set(CMAKE_LBER_LIB "lber" CACHE STRING "Name or full path to lber library") - if(CMAKE_USE_OPENLDAP AND CURL_LDAP_WIN) - message(FATAL_ERROR "Cannot use CURL_LDAP_WIN and CMAKE_USE_OPENLDAP at the same time") + if(CMAKE_USE_OPENLDAP AND USE_WIN32_LDAP) + message(FATAL_ERROR "Cannot use USE_WIN32_LDAP and CMAKE_USE_OPENLDAP at the same time") endif() # Now that we know, we're not using windows LDAP... - if(NOT CURL_LDAP_WIN) + if(NOT USE_WIN32_LDAP) # Check for LDAP + set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_LIBRARIES}) check_library_exists_concat(${CMAKE_LDAP_LIB} ldap_init HAVE_LIBLDAP) check_library_exists_concat(${CMAKE_LBER_LIB} ber_init HAVE_LIBLBER) else() @@ -359,8 +488,8 @@ if(NOT CURL_DISABLE_LDAP) return 0; }" ) - set(CMAKE_REQUIRED_DEFINITIONS "-DLDAP_DEPRECATED=1" "-DWIN32_LEAN_AND_MEAN") - set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_LDAP_LIB}) + set(CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS} -DLDAP_DEPRECATED=1") + list(APPEND CMAKE_REQUIRED_LIBRARIES ${CMAKE_LDAP_LIB}) if(HAVE_LIBLBER) list(APPEND CMAKE_REQUIRED_LIBRARIES ${CMAKE_LBER_LIB}) endif() @@ -394,9 +523,6 @@ check_library_exists_concat("idn" idna_to_ascii_lz HAVE_LIBIDN) # Check for symbol dlopen (same as HAVE_LIBDL) check_library_exists("${CURL_LIBS}" dlopen "" HAVE_DLOPEN) -# For other tests to use the same libraries -set(CMAKE_REQUIRED_LIBRARIES ${CURL_LIBS}) - if(0) # This code not needed for building within CMake. option(CURL_ZLIB "Set to ON to enable building cURL with zlib support." ON) set(HAVE_LIBZ OFF) @@ -409,6 +535,7 @@ if(CURL_ZLIB) set(HAVE_ZLIB ON) set(HAVE_LIBZ ON) list(APPEND CURL_LIBS ${ZLIB_LIBRARIES}) + include_directories(${ZLIB_INCLUDE_DIRS}) endif() endif() endif() @@ -423,67 +550,6 @@ if(CURL_SPECIAL_LIBZ) set(HAVE_ZLIB_H 0) endif() -#----------------------------------------------------------------------------- - -set(USE_SSLEAY OFF) -set(USE_OPENSSL OFF) -set(HAVE_LIBCRYPTO OFF) -set(HAVE_LIBSSL OFF) - -if(CMAKE_USE_OPENSSL) - find_package(OpenSSL) - if(OPENSSL_FOUND) - list(APPEND CURL_LIBS ${OPENSSL_LIBRARIES}) - set(USE_SSLEAY ON) - set(USE_OPENSSL ON) - set(HAVE_LIBCRYPTO ON) - set(HAVE_LIBSSL ON) - include_directories(${OPENSSL_INCLUDE_DIR}) - set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR}) - check_include_file("openssl/crypto.h" HAVE_OPENSSL_CRYPTO_H) - check_include_file("openssl/engine.h" HAVE_OPENSSL_ENGINE_H) - check_include_file("openssl/err.h" HAVE_OPENSSL_ERR_H) - check_include_file("openssl/pem.h" HAVE_OPENSSL_PEM_H) - check_include_file("openssl/pkcs12.h" HAVE_OPENSSL_PKCS12_H) - check_include_file("openssl/rsa.h" HAVE_OPENSSL_RSA_H) - check_include_file("openssl/ssl.h" HAVE_OPENSSL_SSL_H) - check_include_file("openssl/x509.h" HAVE_OPENSSL_X509_H) - check_include_file("openssl/rand.h" HAVE_OPENSSL_RAND_H) - - # Optionally build with a specific CA cert bundle. - if(CURL_CA_BUNDLE) - add_definitions(-DCURL_CA_BUNDLE="${CURL_CA_BUNDLE}") - endif() - # Optionally build with a specific CA cert dir. - if(CURL_CA_PATH) - add_definitions(-DCURL_CA_PATH="${CURL_CA_PATH}") - endif() - endif(OPENSSL_FOUND) -elseif(WIN32) - # Use Windows SSL/TLS native implementation. - add_definitions(-DUSE_SCHANNEL) - set(USE_WINDOWS_SSPI 1) -elseif(APPLE) - # Use OS X SSL/TLS native implementation if available on target version. - if(CMAKE_OSX_DEPLOYMENT_TARGET) - set(OSX_VERSION ${CMAKE_OSX_DEPLOYMENT_TARGET}) - else() - execute_process( - COMMAND sw_vers -productVersion - OUTPUT_VARIABLE OSX_VERSION - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - endif() - if(NOT OSX_VERSION VERSION_LESS 10.6 AND - CMAKE_C_COMPILER_ID MATCHES "GNU|Clang|AppleClang") - add_definitions(-DUSE_DARWINSSL) - list(APPEND CURL_LIBS - "-framework CoreFoundation" - "-framework Security" - ) - endif() -endif() - #libSSH2 option(CMAKE_USE_LIBSSH2 "Use libSSH2" ON) mark_as_advanced(CMAKE_USE_LIBSSH2) @@ -497,6 +563,7 @@ if(CMAKE_USE_LIBSSH2) list(APPEND CURL_LIBS ${LIBSSH2_LIBRARY}) set(CMAKE_REQUIRED_LIBRARIES ${LIBSSH2_LIBRARY}) set(CMAKE_REQUIRED_INCLUDES "${LIBSSH2_INCLUDE_DIR}") + include_directories("${LIBSSH2_INCLUDE_DIR}") set(HAVE_LIBSSH2 ON) set(USE_LIBSSH2 ON) @@ -517,26 +584,87 @@ if(CMAKE_USE_LIBSSH2) endif(LIBSSH2_FOUND) endif(CMAKE_USE_LIBSSH2) -# If we have features.h, then do the _BSD_SOURCE magic -check_include_file("features.h" HAVE_FEATURES_H) +option(CMAKE_USE_GSSAPI "Use GSSAPI implementation (right now only Heimdal is supported with CMake build)" OFF) +mark_as_advanced(CMAKE_USE_GSSAPI) -# Check for header files -if(NOT UNIX) - check_include_file_concat("ws2tcpip.h" HAVE_WS2TCPIP_H) - check_include_file_concat("winsock2.h" HAVE_WINSOCK2_H) +if(CMAKE_USE_GSSAPI) + find_package(GSS) + + set(HAVE_GSSAPI ${GSS_FOUND}) + if(GSS_FOUND) + + message(STATUS "Found ${GSS_FLAVOUR} GSSAPI version: \"${GSS_VERSION}\"") + + set(CMAKE_REQUIRED_INCLUDES ${GSS_INCLUDE_DIR}) + check_include_file_concat("gssapi/gssapi.h" HAVE_GSSAPI_GSSAPI_H) + check_include_file_concat("gssapi/gssapi_generic.h" HAVE_GSSAPI_GSSAPI_GENERIC_H) + check_include_file_concat("gssapi/gssapi_krb5.h" HAVE_GSSAPI_GSSAPI_KRB5_H) + + if(GSS_FLAVOUR STREQUAL "Heimdal") + set(HAVE_GSSHEIMDAL ON) + else() # MIT + set(HAVE_GSSMIT ON) + set(_INCLUDE_LIST "") + if(HAVE_GSSAPI_GSSAPI_H) + list(APPEND _INCLUDE_LIST "gssapi/gssapi.h") + endif() + if(HAVE_GSSAPI_GSSAPI_GENERIC_H) + list(APPEND _INCLUDE_LIST "gssapi/gssapi_generic.h") + endif() + if(HAVE_GSSAPI_GSSAPI_KRB5_H) + list(APPEND _INCLUDE_LIST "gssapi/gssapi_krb5.h") + endif() + + string(REPLACE ";" " " _COMPILER_FLAGS_STR "${GSS_COMPILER_FLAGS}") + string(REPLACE ";" " " _LINKER_FLAGS_STR "${GSS_LINKER_FLAGS}") + + foreach(_dir ${GSS_LINK_DIRECTORIES}) + set(_LINKER_FLAGS_STR "${_LINKER_FLAGS_STR} -L\"${_dir}\"") + endforeach() + + set(CMAKE_REQUIRED_FLAGS "${_COMPILER_FLAGS_STR} ${_LINKER_FLAGS_STR}") + set(CMAKE_REQUIRED_LIBRARIES ${GSS_LIBRARIES}) + check_symbol_exists("GSS_C_NT_HOSTBASED_SERVICE" ${_INCLUDE_LIST} HAVE_GSS_C_NT_HOSTBASED_SERVICE) + if(NOT HAVE_GSS_C_NT_HOSTBASED_SERVICE) + set(HAVE_OLD_GSSMIT ON) + endif() + + endif() + + include_directories(${GSS_INCLUDE_DIR}) + link_directories(${GSS_LINK_DIRECTORIES}) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${GSS_COMPILER_FLAGS}") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${GSS_LINKER_FLAGS}") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${GSS_LINKER_FLAGS}") + list(APPEND CURL_LIBS ${GSS_LIBRARIES}) + + else() + message(WARNING "GSSAPI support has been requested but no supporting libraries found. Skipping.") + endif() +endif() + +option(ENABLE_UNIX_SOCKETS "Define if you want Unix domain sockets support" ON) +if(ENABLE_UNIX_SOCKETS) + include(CheckStructHasMember) + check_struct_has_member("struct sockaddr_un" sun_path "sys/un.h" USE_UNIX_SOCKETS) else() - set(HAVE_WS2TCPIP_H 0) - set(HAVE_WINSOCK2_H 0) + unset(USE_UNIX_SOCKETS CACHE) endif() -check_include_file_concat("stdio.h" HAVE_STDIO_H) + +# Check for header files if(NOT UNIX) check_include_file_concat("windows.h" HAVE_WINDOWS_H) check_include_file_concat("winsock.h" HAVE_WINSOCK_H) + check_include_file_concat("ws2tcpip.h" HAVE_WS2TCPIP_H) + check_include_file_concat("winsock2.h" HAVE_WINSOCK2_H) else() set(HAVE_WINDOWS_H 0) set(HAVE_WINSOCK_H 0) + set(HAVE_WS2TCPIP_H 0) + set(HAVE_WINSOCK2_H 0) endif() +check_include_file_concat("stdio.h" HAVE_STDIO_H) check_include_file_concat("inttypes.h" HAVE_INTTYPES_H) check_include_file_concat("sys/filio.h" HAVE_SYS_FILIO_H) check_include_file_concat("sys/ioctl.h" HAVE_SYS_IOCTL_H) @@ -561,9 +689,6 @@ check_include_file_concat("des.h" HAVE_DES_H) check_include_file_concat("err.h" HAVE_ERR_H) check_include_file_concat("errno.h" HAVE_ERRNO_H) check_include_file_concat("fcntl.h" HAVE_FCNTL_H) -check_include_file_concat("gssapi/gssapi.h" HAVE_GSSAPI_GSSAPI_H) -check_include_file_concat("gssapi/gssapi_generic.h" HAVE_GSSAPI_GSSAPI_GENERIC_H) -check_include_file_concat("gssapi/gssapi_krb5.h" HAVE_GSSAPI_GSSAPI_KRB5_H) check_include_file_concat("idn-free.h" HAVE_IDN_FREE_H) check_include_file_concat("ifaddrs.h" HAVE_IFADDRS_H) check_include_file_concat("io.h" HAVE_IO_H) @@ -636,6 +761,12 @@ find_file(RANDOM_FILE urandom /dev) mark_as_advanced(RANDOM_FILE) # Check for some functions that are used +if(HAVE_LIBWS2_32) + set(CMAKE_REQUIRED_LIBRARIES ws2_32) +elseif(HAVE_LIBSOCKET) + set(CMAKE_REQUIRED_LIBRARIES socket) +endif() + check_symbol_exists(basename "${CURL_INCLUDES}" HAVE_BASENAME) check_symbol_exists(socket "${CURL_INCLUDES}" HAVE_SOCKET) check_symbol_exists(poll "${CURL_INCLUDES}" HAVE_POLL) @@ -678,7 +809,6 @@ if(CMAKE_USE_OPENSSL) HAVE_CRYPTO_CLEANUP_ALL_EX_DATA) if(HAVE_LIBCRYPTO AND HAVE_LIBSSL) set(USE_OPENSSL 1) - set(USE_SSLEAY 1) endif(HAVE_LIBCRYPTO AND HAVE_LIBSSL) endif(CMAKE_USE_OPENSSL) check_symbol_exists(gmtime_r "${CURL_INCLUDES}" HAVE_GMTIME_R) @@ -699,6 +829,7 @@ check_symbol_exists(strerror_r "${CURL_INCLUDES}" HAVE_STRERROR_R) check_symbol_exists(siginterrupt "${CURL_INCLUDES}" HAVE_SIGINTERRUPT) check_symbol_exists(perror "${CURL_INCLUDES}" HAVE_PERROR) check_symbol_exists(fork "${CURL_INCLUDES}" HAVE_FORK) +check_symbol_exists(getaddrinfo "${CURL_INCLUDES}" HAVE_GETADDRINFO) check_symbol_exists(freeaddrinfo "${CURL_INCLUDES}" HAVE_FREEADDRINFO) check_symbol_exists(freeifaddrs "${CURL_INCLUDES}" HAVE_FREEIFADDRS) check_symbol_exists(pipe "${CURL_INCLUDES}" HAVE_PIPE) @@ -737,12 +868,7 @@ if(NOT HAVE_STRICMP) set(HAVE_LDAP_URL_PARSE 1) endif(NOT HAVE_STRICMP) - - # Do curl specific tests -if(HAVE_LIBWS2_32) - set(CMAKE_REQUIRED_LIBRARIES ws2_32) -endif() foreach(CURL_TEST HAVE_FCNTL_O_NONBLOCK HAVE_IOCTLSOCKET @@ -929,24 +1055,6 @@ if(MSVC) add_definitions(-D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE) endif(MSVC) -# Sets up the dependencies (zlib, OpenSSL, etc.) of a cURL subproject according to options. -# TODO This is far to be complete! -function(SETUP_CURL_DEPENDENCIES TARGET_NAME) - if(CURL_ZLIB AND ZLIB_FOUND) - include_directories(${ZLIB_INCLUDE_DIR}) - endif() - - if(CMAKE_USE_OPENSSL AND OPENSSL_FOUND) - include_directories(${OPENSSL_INCLUDE_DIR}) - endif() - - if(CMAKE_USE_LIBSSH2 AND LIBSSH2_FOUND) - include_directories(${LIBSSH2_INCLUDE_DIR}) - endif() - - target_link_libraries(${TARGET_NAME} ${CURL_LIBS}) -endfunction() - # Ugly (but functional) way to include "Makefile.inc" by transforming it (= regenerate it). function(TRANSFORM_MAKEFILE_INC INPUT_FILE OUTPUT_FILE) file(READ ${INPUT_FILE} MAKEFILE_INC_TEXT) @@ -984,6 +1092,133 @@ install(FILES COPYING DESTINATION ${CMAKE_DOC_DIR}/cmcurl) #----------------------------------------------------------------------------- if(0) # This code not needed for building within CMake. +# TODO support GNUTLS, NSS, POLARSSL, AXTLS, CYASSL, WINSSL, DARWINSSL +if(USE_OPENSSL) + set(SSL_ENABLED 1) +endif() + +# Helper to populate a list (_items) with a label when conditions (the remaining +# args) are satisfied +function(_add_if label) + # TODO need to disable policy CMP0054 (CMake 3.1) to allow this indirection + if(${ARGN}) + set(_items ${_items} "${label}" PARENT_SCOPE) + endif() +endfunction() + +# Clear list and try to detect available features +set(_items) +_add_if("SSL" SSL_ENABLED) +_add_if("IPv6" ENABLE_IPV6) +_add_if("unix-sockets" USE_UNIX_SOCKETS) +_add_if("libz" HAVE_LIBZ) +_add_if("AsynchDNS" USE_ARES OR USE_THREADS_POSIX) +_add_if("IDN" HAVE_LIBIDN) +# TODO SSP1 (WinSSL) check is missing +_add_if("SSPI" USE_WINDOWS_SSPI) +_add_if("GSS-API" HAVE_GSSAPI) +# TODO SSP1 missing for SPNEGO +_add_if("SPNEGO" NOT CURL_DISABLE_CRYPTO_AUTH AND + (HAVE_GSSAPI OR USE_WINDOWS_SSPI)) +_add_if("Kerberos" NOT CURL_DISABLE_CRYPTO_AUTH AND + (HAVE_GSSAPI OR USE_WINDOWS_SSPI)) +# NTLM support requires crypto function adaptions from various SSL libs +# TODO alternative SSL libs tests for SSP1, GNUTLS, NSS, DARWINSSL +if(NOT CURL_DISABLE_CRYPTO_AUTH AND (USE_OPENSSL OR + USE_WINDOWS_SSPI OR GNUTLS_ENABLED OR NSS_ENABLED OR DARWINSSL_ENABLED)) + _add_if("NTLM" 1) + # TODO missing option (autoconf: --enable-ntlm-wb) + _add_if("NTLM_WB" NOT CURL_DISABLE_HTTP AND NTLM_WB_ENABLED) +endif() +# TODO missing option (--enable-tls-srp), depends on GNUTLS_SRP/OPENSSL_SRP +_add_if("TLS-SRP" USE_TLS_SRP) +# TODO option --with-nghttp2 tests for nghttp2 lib and nghttp2/nghttp2.h header +_add_if("HTTP2" USE_NGHTTP2) +string(REPLACE ";" " " SUPPORT_FEATURES "${_items}") +message(STATUS "Enabled features: ${SUPPORT_FEATURES}") + +# Clear list and try to detect available protocols +set(_items) +_add_if("HTTP" NOT CURL_DISABLE_HTTP) +_add_if("HTTPS" NOT CURL_DISABLE_HTTP AND SSL_ENABLED) +_add_if("FTP" NOT CURL_DISABLE_FTP) +_add_if("FTPS" NOT CURL_DISABLE_FTP AND SSL_ENABLED) +_add_if("FILE" NOT CURL_DISABLE_FILE) +_add_if("TELNET" NOT CURL_DISABLE_TELNET) +_add_if("LDAP" NOT CURL_DISABLE_LDAP) +# CURL_DISABLE_LDAP implies CURL_DISABLE_LDAPS +# TODO check HAVE_LDAP_SSL (in autoconf this is enabled with --enable-ldaps) +_add_if("LDAPS" NOT CURL_DISABLE_LDAPS AND + ((USE_OPENLDAP AND SSL_ENABLED) OR + (NOT USE_OPENLDAP AND HAVE_LDAP_SSL))) +_add_if("DICT" NOT CURL_DISABLE_DICT) +_add_if("TFTP" NOT CURL_DISABLE_TFTP) +_add_if("GOPHER" NOT CURL_DISABLE_GOPHER) +_add_if("POP3" NOT CURL_DISABLE_POP3) +_add_if("POP3S" NOT CURL_DISABLE_POP3 AND SSL_ENABLED) +_add_if("IMAP" NOT CURL_DISABLE_IMAP) +_add_if("IMAPS" NOT CURL_DISABLE_IMAP AND SSL_ENABLED) +_add_if("SMTP" NOT CURL_DISABLE_SMTP) +_add_if("SMTPS" NOT CURL_DISABLE_SMTP AND SSL_ENABLED) +_add_if("SCP" USE_LIBSSH2) +_add_if("SFTP" USE_LIBSSH2) +_add_if("RTSP" NOT CURL_DISABLE_RTSP) +_add_if("RTMP" USE_LIBRTMP) +list(SORT _items) +string(REPLACE ";" " " SUPPORT_PROTOCOLS "${_items}") +message(STATUS "Enabled protocols: ${SUPPORT_PROTOCOLS}") + +# curl-config needs the following options to be set. +set(CC "${CMAKE_C_COMPILER}") +# TODO probably put a -D... options here? +set(CONFIGURE_OPTIONS "") +# TODO when to set "-DCURL_STATICLIB" for CPPFLAG_CURL_STATICLIB? +set(CPPFLAG_CURL_STATICLIB "") +# TODO need to set this (see CURL_CHECK_CA_BUNDLE in acinclude.m4) +set(CURL_CA_BUNDLE "") +set(CURLVERSION "${CURL_VERSION}") +set(ENABLE_SHARED "yes") +if(CURL_STATICLIB) + # Broken: LIBCURL_LIBS below; .a lib is not built + message(WARNING "Static linking is broken!") + set(ENABLE_STATIC "no") +else() + set(ENABLE_STATIC "no") +endif() +set(exec_prefix "\${prefix}") +set(includedir "\${prefix}/include") +set(LDFLAGS "${CMAKE_SHARED_LINKER_FLAGS}") +set(LIBCURL_LIBS "") +set(libdir "${CMAKE_INSTALL_PREFIX}/lib") +# TODO CURL_LIBS also contains absolute paths which don't work with static -l... +foreach(_lib ${CMAKE_C_IMPLICIT_LINK_LIBRARIES} ${CURL_LIBS}) + set(LIBCURL_LIBS "${LIBCURL_LIBS} -l${_lib}") +endforeach() +# "a" (Linux) or "lib" (Windows) +string(REPLACE "." "" libext "${CMAKE_STATIC_LIBRARY_SUFFIX}") +set(prefix "${CMAKE_INSTALL_PREFIX}") +# Set this to "yes" to append all libraries on which -lcurl is dependent +set(REQUIRE_LIB_DEPS "no") +# SUPPORT_FEATURES +# SUPPORT_PROTOCOLS +set(VERSIONNUM "${CURL_VERSION_NUM}") + +# Finally generate a "curl-config" matching this config +configure_file("${CURL_SOURCE_DIR}/curl-config.in" + "${CURL_BINARY_DIR}/curl-config" @ONLY) +install(FILES "${CMAKE_BINARY_DIR}/curl-config" + DESTINATION bin + PERMISSIONS + OWNER_READ OWNER_WRITE OWNER_EXECUTE + GROUP_READ GROUP_EXECUTE + WORLD_READ WORLD_EXECUTE) + +# Finally generate a pkg-config file matching this config +configure_file("${CURL_SOURCE_DIR}/libcurl.pc.in" + "${CURL_BINARY_DIR}/libcurl.pc" @ONLY) +install(FILES "${CMAKE_BINARY_DIR}/libcurl.pc" + DESTINATION lib/pkgconfig) + # This needs to be run very last so other parts of the scripts can take advantage of this. 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") diff --git a/Utilities/cmcurl/COPYING b/Utilities/cmcurl/COPYING index dd990b6..6b5d59f 100644 --- a/Utilities/cmcurl/COPYING +++ b/Utilities/cmcurl/COPYING @@ -1,6 +1,6 @@ COPYRIGHT AND PERMISSION NOTICE -Copyright (c) 1996 - 2014, Daniel Stenberg, <daniel@haxx.se>. +Copyright (c) 1996 - 2015, Daniel Stenberg, <daniel@haxx.se>. All rights reserved. diff --git a/Utilities/cmcurl/include/curl/curl.h b/Utilities/cmcurl/include/curl/curl.h index 40d0b81..86ce1ff 100644 --- a/Utilities/cmcurl/include/curl/curl.h +++ b/Utilities/cmcurl/include/curl/curl.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -521,6 +521,9 @@ typedef enum { CURLE_CHUNK_FAILED, /* 88 - chunk callback reported error */ CURLE_NO_CONNECTION_AVAILABLE, /* 89 - No connection available, the session will be queued */ + CURLE_SSL_PINNEDPUBKEYNOTMATCH, /* 90 - specified pinned public key did not + match */ + CURLE_SSL_INVALIDCERTSTATUS, /* 91 - invalid certificate status */ CURL_LAST /* never use! */ } CURLcode; @@ -722,6 +725,10 @@ typedef enum { servers, a user can this way allow the vulnerability back. */ #define CURLSSLOPT_ALLOW_BEAST (1<<0) +/* - NO_REVOKE tells libcurl to disable certificate revocation checks for those + SSL backends where such behavior is present. */ +#define CURLSSLOPT_NO_REVOKE (1<<1) + #ifndef CURL_NO_OLDIES /* define this to test if your app builds with all the obsolete stuff removed! */ @@ -803,6 +810,8 @@ typedef enum { #define CURLPROTO_RTMPS (1<<23) #define CURLPROTO_RTMPTS (1<<24) #define CURLPROTO_GOPHER (1<<25) +#define CURLPROTO_SMB (1<<26) +#define CURLPROTO_SMBS (1<<27) #define CURLPROTO_ALL (~0) /* enable everything */ /* long may be 32 or 64 bits, but we should never depend on anything else @@ -841,7 +850,7 @@ typedef enum { CINIT(WRITEDATA, OBJECTPOINT, 1), /* The full URL to get/put */ - CINIT(URL, OBJECTPOINT, 2), + CINIT(URL, OBJECTPOINT, 2), /* Port number to connect to, if other than default. */ CINIT(PORT, LONG, 3), @@ -985,7 +994,7 @@ typedef enum { CINIT(HEADER, LONG, 42), /* throw the header out too */ CINIT(NOPROGRESS, LONG, 43), /* shut off the progress meter */ CINIT(NOBODY, LONG, 44), /* use HEAD to get http document */ - CINIT(FAILONERROR, LONG, 45), /* no output on http error codes >= 300 */ + CINIT(FAILONERROR, LONG, 45), /* no output on http error codes >= 400 */ CINIT(UPLOAD, LONG, 46), /* this is an upload */ CINIT(POST, LONG, 47), /* HTTP POST method */ CINIT(DIRLISTONLY, LONG, 48), /* bare names when listing directories */ @@ -1611,6 +1620,31 @@ typedef enum { /* Pass in a bitmask of "header options" */ CINIT(HEADEROPT, LONG, 229), + /* The public key in DER form used to validate the peer public key + this option is used only if SSL_VERIFYPEER is true */ + CINIT(PINNEDPUBLICKEY, OBJECTPOINT, 230), + + /* Path to Unix domain socket */ + CINIT(UNIX_SOCKET_PATH, OBJECTPOINT, 231), + + /* Set if we should verify the certificate status. */ + CINIT(SSL_VERIFYSTATUS, LONG, 232), + + /* Set if we should enable TLS false start. */ + CINIT(SSL_FALSESTART, LONG, 233), + + /* Do not squash dot-dot sequences */ + CINIT(PATH_AS_IS, LONG, 234), + + /* Proxy Service Name */ + CINIT(PROXY_SERVICE_NAME, OBJECTPOINT, 235), + + /* Service Name */ + CINIT(SERVICE_NAME, OBJECTPOINT, 236), + + /* Wait/don't wait for pipe/mutex to clarify */ + CINIT(PIPEWAIT, LONG, 237), + CURLOPT_LASTENTRY /* the last unused */ } CURLoption; @@ -1647,8 +1681,8 @@ typedef enum { option might be handy to force libcurl to use a specific IP version. */ #define CURL_IPRESOLVE_WHATEVER 0 /* default, resolves addresses to all IP versions that your system allows */ -#define CURL_IPRESOLVE_V4 1 /* resolve to ipv4 addresses */ -#define CURL_IPRESOLVE_V6 2 /* resolve to ipv6 addresses */ +#define CURL_IPRESOLVE_V4 1 /* resolve to IPv4 addresses */ +#define CURL_IPRESOLVE_V6 2 /* resolve to IPv6 addresses */ /* three convenient "aliases" that follow the name scheme better */ #define CURLOPT_RTSPHEADER CURLOPT_HTTPHEADER @@ -1665,6 +1699,11 @@ enum { CURL_HTTP_VERSION_LAST /* *ILLEGAL* http version */ }; +/* Convenience definition simple because the name of the version is HTTP/2 and + not 2.0. The 2_0 version of the enum name was set while the version was + still planned to be 2.0 and we stick to it for compatibility. */ +#define CURL_HTTP_VERSION_2 CURL_HTTP_VERSION_2_0 + /* * Public API enums for RTSP requests */ @@ -2028,7 +2067,7 @@ typedef enum { CURLSSLBACKEND_OPENSSL = 1, CURLSSLBACKEND_GNUTLS = 2, CURLSSLBACKEND_NSS = 3, - CURLSSLBACKEND_QSOSSL = 4, + CURLSSLBACKEND_OBSOLETE4 = 4, /* Was QSOSSL. */ CURLSSLBACKEND_GSKIT = 5, CURLSSLBACKEND_POLARSSL = 6, CURLSSLBACKEND_CYASSL = 7, @@ -2235,25 +2274,30 @@ typedef struct { } curl_version_info_data; -#define CURL_VERSION_IPV6 (1<<0) /* IPv6-enabled */ -#define CURL_VERSION_KERBEROS4 (1<<1) /* kerberos auth is supported */ -#define CURL_VERSION_SSL (1<<2) /* SSL options are present */ -#define CURL_VERSION_LIBZ (1<<3) /* libz features are present */ -#define CURL_VERSION_NTLM (1<<4) /* NTLM auth is supported */ -#define CURL_VERSION_GSSNEGOTIATE (1<<5) /* Negotiate auth support - (deprecated) */ -#define CURL_VERSION_DEBUG (1<<6) /* built with debug capabilities */ -#define CURL_VERSION_ASYNCHDNS (1<<7) /* asynchronous dns resolves */ -#define CURL_VERSION_SPNEGO (1<<8) /* SPNEGO auth is supported */ -#define CURL_VERSION_LARGEFILE (1<<9) /* supports files bigger than 2GB */ -#define CURL_VERSION_IDN (1<<10) /* International Domain Names support */ -#define CURL_VERSION_SSPI (1<<11) /* SSPI is supported */ -#define CURL_VERSION_CONV (1<<12) /* character conversions supported */ -#define CURL_VERSION_CURLDEBUG (1<<13) /* debug memory tracking supported */ -#define CURL_VERSION_TLSAUTH_SRP (1<<14) /* TLS-SRP auth is supported */ -#define CURL_VERSION_NTLM_WB (1<<15) /* NTLM delegating to winbind helper */ -#define CURL_VERSION_HTTP2 (1<<16) /* HTTP2 support built-in */ -#define CURL_VERSION_GSSAPI (1<<17) /* GSS-API is supported */ +#define CURL_VERSION_IPV6 (1<<0) /* IPv6-enabled */ +#define CURL_VERSION_KERBEROS4 (1<<1) /* Kerberos V4 auth is supported + (deprecated) */ +#define CURL_VERSION_SSL (1<<2) /* SSL options are present */ +#define CURL_VERSION_LIBZ (1<<3) /* libz features are present */ +#define CURL_VERSION_NTLM (1<<4) /* NTLM auth is supported */ +#define CURL_VERSION_GSSNEGOTIATE (1<<5) /* Negotiate auth is supported + (deprecated) */ +#define CURL_VERSION_DEBUG (1<<6) /* Built with debug capabilities */ +#define CURL_VERSION_ASYNCHDNS (1<<7) /* Asynchronous DNS resolves */ +#define CURL_VERSION_SPNEGO (1<<8) /* SPNEGO auth is supported */ +#define CURL_VERSION_LARGEFILE (1<<9) /* Supports files larger than 2GB */ +#define CURL_VERSION_IDN (1<<10) /* Internationized Domain Names are + supported */ +#define CURL_VERSION_SSPI (1<<11) /* Built against Windows SSPI */ +#define CURL_VERSION_CONV (1<<12) /* Character conversions supported */ +#define CURL_VERSION_CURLDEBUG (1<<13) /* Debug memory tracking supported */ +#define CURL_VERSION_TLSAUTH_SRP (1<<14) /* TLS-SRP auth is supported */ +#define CURL_VERSION_NTLM_WB (1<<15) /* NTLM delegation to winbind helper + is suported */ +#define CURL_VERSION_HTTP2 (1<<16) /* HTTP2 support built-in */ +#define CURL_VERSION_GSSAPI (1<<17) /* Built against a GSS-API library */ +#define CURL_VERSION_KERBEROS5 (1<<18) /* Kerberos V5 auth is supported */ +#define CURL_VERSION_UNIX_SOCKETS (1<<19) /* Unix domain sockets support */ /* * NAME curl_version_info() diff --git a/Utilities/cmcurl/include/curl/curlver.h b/Utilities/cmcurl/include/curl/curlver.h index c0cb509..a41fdef 100644 --- a/Utilities/cmcurl/include/curl/curlver.h +++ b/Utilities/cmcurl/include/curl/curlver.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -26,16 +26,16 @@ a script at release-time. This was made its own header file in 7.11.2 */ /* This is the global package copyright */ -#define LIBCURL_COPYRIGHT "1996 - 2014 Daniel Stenberg, <daniel@haxx.se>." +#define LIBCURL_COPYRIGHT "1996 - 2015 Daniel Stenberg, <daniel@haxx.se>." /* This is the version number of the libcurl package from which this header file origins: */ -#define LIBCURL_VERSION "7.38.0" +#define LIBCURL_VERSION "7.44.0" /* The numeric version number is also available "in parts" by using these defines: */ #define LIBCURL_VERSION_MAJOR 7 -#define LIBCURL_VERSION_MINOR 38 +#define LIBCURL_VERSION_MINOR 44 #define LIBCURL_VERSION_PATCH 0 /* This is the numeric version of the libcurl version number, meant for easier @@ -52,8 +52,12 @@ This 6-digit (24 bits) hexadecimal number does not show pre-release number, and it is always a greater number in a more recent release. It makes comparisons with greater than and less than work. + + Note: This define is the full hex number and _does not_ use the + 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 0x072600 +#define LIBCURL_VERSION_NUM 0x072C00 /* * This is the date and time when the full source package was created. The @@ -66,4 +70,8 @@ */ #define LIBCURL_TIMESTAMP "DEV" +#define CURL_VERSION_BITS(x,y,z) ((x)<<16|(y)<<8|z) +#define CURL_AT_LEAST_VERSION(x,y,z) \ + (LIBCURL_VERSION_NUM >= CURL_VERSION_BITS(x, y, z)) + #endif /* __CURL_CURLVER_H */ diff --git a/Utilities/cmcurl/include/curl/mprintf.h b/Utilities/cmcurl/include/curl/mprintf.h index cc9e7f5..c6b0d76 100644 --- a/Utilities/cmcurl/include/curl/mprintf.h +++ b/Utilities/cmcurl/include/curl/mprintf.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -57,15 +57,8 @@ CURL_EXTERN char *curl_mvaprintf(const char *format, va_list args); # undef vaprintf # define printf curl_mprintf # define fprintf curl_mfprintf -#ifdef CURLDEBUG -/* When built with CURLDEBUG we define away the sprintf functions since we - don't want internal code to be using them */ -# define sprintf sprintf_was_used -# define vsprintf vsprintf_was_used -#else # define sprintf curl_msprintf # define vsprintf curl_mvsprintf -#endif # define snprintf curl_msnprintf # define vprintf curl_mvprintf # define vfprintf curl_mvfprintf diff --git a/Utilities/cmcurl/include/curl/multi.h b/Utilities/cmcurl/include/curl/multi.h index 10d6006..0f1561d 100644 --- a/Utilities/cmcurl/include/curl/multi.h +++ b/Utilities/cmcurl/include/curl/multi.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -74,6 +74,11 @@ typedef enum { curl_multi_perform() and CURLM_CALL_MULTI_PERFORM */ #define CURLM_CALL_MULTI_SOCKET CURLM_CALL_MULTI_PERFORM +/* bitmask bits for CURLMOPT_PIPELINING */ +#define CURLPIPE_NOTHING 0L +#define CURLPIPE_HTTP1 1L +#define CURLPIPE_MULTIPLEX 2L + typedef enum { CURLMSG_NONE, /* first, not used */ CURLMSG_DONE, /* This easy handle has completed. 'result' contains @@ -365,6 +370,12 @@ typedef enum { /* maximum number of open connections in total */ CINIT(MAX_TOTAL_CONNECTIONS, LONG, 13), + /* This is the server push callback function pointer */ + CINIT(PUSHFUNCTION, FUNCTIONPOINT, 14), + + /* This is the argument passed to the server push callback */ + CINIT(PUSHDATA, OBJECTPOINT, 15), + CURLMOPT_LASTENTRY /* the last unused */ } CURLMoption; @@ -392,6 +403,31 @@ CURL_EXTERN CURLMcode curl_multi_setopt(CURLM *multi_handle, CURL_EXTERN CURLMcode curl_multi_assign(CURLM *multi_handle, curl_socket_t sockfd, void *sockp); + +/* + * Name: curl_push_callback + * + * Desc: This callback gets called when a new stream is being pushed by the + * server. It approves or denies the new stream. + * + * Returns: CURL_PUSH_OK or CURL_PUSH_DENY. + */ +#define CURL_PUSH_OK 0 +#define CURL_PUSH_DENY 1 + +struct curl_pushheaders; /* forward declaration only */ + +CURL_EXTERN char *curl_pushheader_bynum(struct curl_pushheaders *h, + size_t num); +CURL_EXTERN char *curl_pushheader_byname(struct curl_pushheaders *h, + const char *name); + +typedef int (*curl_push_callback)(CURL *parent, + CURL *easy, + size_t num_headers, + struct curl_pushheaders *headers, + void *userp); + #ifdef __cplusplus } /* end of extern "C" */ #endif diff --git a/Utilities/cmcurl/include/curl/typecheck-gcc.h b/Utilities/cmcurl/include/curl/typecheck-gcc.h index 69d41a2..13fb0fa 100644 --- a/Utilities/cmcurl/include/curl/typecheck-gcc.h +++ b/Utilities/cmcurl/include/curl/typecheck-gcc.h @@ -270,6 +270,8 @@ _CURL_WARNING(_curl_easy_getinfo_err_curl_slist, (option) == CURLOPT_DNS_LOCAL_IP4 || \ (option) == CURLOPT_DNS_LOCAL_IP6 || \ (option) == CURLOPT_LOGIN_OPTIONS || \ + (option) == CURLOPT_PROXY_SERVICE_NAME || \ + (option) == CURLOPT_SERVICE_NAME || \ 0) /* evaluates to true if option takes a curl_write_callback argument */ diff --git a/Utilities/cmcurl/lib/CMakeLists.txt b/Utilities/cmcurl/lib/CMakeLists.txt index a4621c1..0d7b717 100644 --- a/Utilities/cmcurl/lib/CMakeLists.txt +++ b/Utilities/cmcurl/lib/CMakeLists.txt @@ -48,25 +48,6 @@ endif() # ) # ENDIF(NOT HAVE_STRTOLL AND NOT HAVE__STRTOI64) -if(HAVE_FEATURES_H) - set_source_files_properties( - cookie.c - easy.c - formdata.c - getenv.c - nonblock.c - hash.c - http.c - if2ip.c - mprintf.c - multi.c - sendf.c - telnet.c - transfer.c - url.c - COMPILE_FLAGS -D_BSD_SOURCE) -endif(HAVE_FEATURES_H) - # The rest of the build @@ -76,7 +57,7 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../include) include_directories(${CMAKE_CURRENT_BINARY_DIR}/..) include_directories(${CMAKE_CURRENT_SOURCE_DIR}) include_directories(${CMAKE_CURRENT_BINARY_DIR}) -if(CURL_USE_ARES) +if(USE_ARES) include_directories(${CARES_INCLUDE_DIR}) endif() @@ -129,8 +110,6 @@ endif() set_target_properties(${LIB_NAME} PROPERTIES COMPILE_DEFINITIONS BUILDING_LIBCURL) -setup_curl_dependencies(${LIB_NAME}) - if(0) # This code not needed for building within CMake. # Remove the "lib" prefix since the library is already named "libcurl". set_target_properties(${LIB_NAME} PROPERTIES PREFIX "") @@ -143,5 +122,8 @@ if(WIN32) endif() endif() -install(TARGETS ${LIB_NAME} DESTINATION lib) +install(TARGETS ${LIB_NAME} + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib + RUNTIME DESTINATION bin) endif() diff --git a/Utilities/cmcurl/lib/Makefile.inc b/Utilities/cmcurl/lib/Makefile.inc index 462d72a..d444a6b 100644 --- a/Utilities/cmcurl/lib/Makefile.inc +++ b/Utilities/cmcurl/lib/Makefile.inc @@ -5,7 +5,7 @@ # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # -# Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. +# Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms @@ -20,50 +20,52 @@ # ########################################################################### -LIB_VTLS_CFILES = vtls/openssl.c vtls/gtls.c vtls/vtls.c vtls/nss.c \ - vtls/qssl.c vtls/polarssl.c vtls/polarssl_threadlock.c vtls/axtls.c \ - vtls/cyassl.c vtls/curl_schannel.c vtls/curl_darwinssl.c vtls/gskit.c +LIB_VTLS_CFILES = vtls/openssl.c vtls/gtls.c vtls/vtls.c vtls/nss.c \ + vtls/polarssl.c vtls/polarssl_threadlock.c vtls/axtls.c \ + vtls/cyassl.c vtls/schannel.c vtls/darwinssl.c vtls/gskit.c -LIB_VTLS_HFILES = vtls/qssl.h vtls/openssl.h vtls/vtls.h vtls/gtls.h \ - vtls/nssg.h vtls/polarssl.h vtls/polarssl_threadlock.h vtls/axtls.h \ - vtls/cyassl.h vtls/curl_schannel.h vtls/curl_darwinssl.h vtls/gskit.h +LIB_VTLS_HFILES = vtls/openssl.h vtls/vtls.h vtls/gtls.h \ + vtls/nssg.h vtls/polarssl.h vtls/polarssl_threadlock.h vtls/axtls.h \ + vtls/cyassl.h vtls/schannel.h vtls/darwinssl.h vtls/gskit.h -LIB_CFILES = file.c timeval.c base64.c hostip.c progress.c formdata.c \ - cookie.c http.c sendf.c ftp.c url.c dict.c if2ip.c speedcheck.c \ - ldap.c version.c getenv.c escape.c mprintf.c telnet.c netrc.c \ - getinfo.c transfer.c strequal.c easy.c security.c curl_fnmatch.c \ - fileinfo.c ftplistparser.c wildcard.c krb5.c memdebug.c http_chunks.c \ - strtok.c connect.c llist.c hash.c multi.c content_encoding.c share.c \ - http_digest.c md4.c md5.c http_negotiate.c inet_pton.c strtoofft.c \ - strerror.c amigaos.c hostasyn.c hostip4.c hostip6.c hostsyn.c \ - inet_ntop.c parsedate.c select.c tftp.c splay.c strdup.c socks.c \ - ssh.c rawstr.c curl_addrinfo.c socks_gssapi.c socks_sspi.c \ - curl_sspi.c slist.c nonblock.c curl_memrchr.c imap.c pop3.c smtp.c \ - pingpong.c rtsp.c curl_threads.c warnless.c hmac.c curl_rtmp.c \ - openldap.c curl_gethostname.c gopher.c idn_win32.c \ - http_negotiate_sspi.c http_proxy.c non-ascii.c asyn-ares.c \ - asyn-thread.c curl_gssapi.c curl_ntlm.c curl_ntlm_wb.c \ - curl_ntlm_core.c curl_ntlm_msgs.c curl_sasl.c curl_multibyte.c \ - hostcheck.c bundles.c conncache.c pipeline.c dotdot.c x509asn1.c \ - http2.c curl_sasl_sspi.c +LIB_CFILES = file.c timeval.c base64.c hostip.c progress.c formdata.c \ + cookie.c http.c sendf.c ftp.c url.c dict.c if2ip.c speedcheck.c \ + ldap.c version.c getenv.c escape.c mprintf.c telnet.c netrc.c \ + getinfo.c transfer.c strequal.c easy.c security.c curl_fnmatch.c \ + fileinfo.c ftplistparser.c wildcard.c krb5.c memdebug.c http_chunks.c \ + strtok.c connect.c llist.c hash.c multi.c content_encoding.c share.c \ + http_digest.c md4.c md5.c http_negotiate.c inet_pton.c strtoofft.c \ + strerror.c amigaos.c hostasyn.c hostip4.c hostip6.c hostsyn.c \ + inet_ntop.c parsedate.c select.c tftp.c splay.c strdup.c socks.c \ + ssh.c rawstr.c curl_addrinfo.c socks_gssapi.c socks_sspi.c \ + curl_sspi.c slist.c nonblock.c curl_memrchr.c imap.c pop3.c smtp.c \ + pingpong.c rtsp.c curl_threads.c warnless.c hmac.c curl_rtmp.c \ + openldap.c curl_gethostname.c gopher.c idn_win32.c \ + http_negotiate_sspi.c http_proxy.c non-ascii.c asyn-ares.c \ + asyn-thread.c curl_gssapi.c curl_ntlm.c curl_ntlm_wb.c \ + curl_ntlm_core.c curl_ntlm_msgs.c curl_sasl.c curl_multibyte.c \ + hostcheck.c conncache.c pipeline.c dotdot.c x509asn1.c \ + http2.c curl_sasl_sspi.c smb.c curl_sasl_gssapi.c curl_endian.c \ + curl_des.c -LIB_HFILES = arpa_telnet.h netrc.h file.h timeval.h hostip.h progress.h \ - formdata.h cookie.h http.h sendf.h ftp.h url.h dict.h if2ip.h \ - speedcheck.h urldata.h curl_ldap.h escape.h telnet.h getinfo.h \ - strequal.h curl_sec.h memdebug.h http_chunks.h curl_fnmatch.h \ - wildcard.h fileinfo.h ftplistparser.h strtok.h connect.h llist.h \ - hash.h content_encoding.h share.h curl_md4.h curl_md5.h http_digest.h \ - http_negotiate.h inet_pton.h amigaos.h strtoofft.h strerror.h \ - inet_ntop.h curlx.h curl_memory.h curl_setup.h transfer.h select.h \ - easyif.h multiif.h parsedate.h tftp.h sockaddr.h splay.h strdup.h \ - socks.h ssh.h curl_base64.h rawstr.h curl_addrinfo.h curl_sspi.h \ - slist.h nonblock.h curl_memrchr.h imap.h pop3.h smtp.h pingpong.h \ - rtsp.h curl_threads.h warnless.h curl_hmac.h curl_rtmp.h \ - curl_gethostname.h gopher.h http_proxy.h non-ascii.h asyn.h \ - curl_ntlm.h curl_gssapi.h curl_ntlm_wb.h curl_ntlm_core.h \ - curl_ntlm_msgs.h curl_sasl.h curl_multibyte.h hostcheck.h bundles.h \ - conncache.h curl_setup_once.h multihandle.h setup-vms.h pipeline.h \ - dotdot.h x509asn1.h http2.h sigpipe.h +LIB_HFILES = arpa_telnet.h netrc.h file.h timeval.h hostip.h progress.h \ + formdata.h cookie.h http.h sendf.h ftp.h url.h dict.h if2ip.h \ + speedcheck.h urldata.h curl_ldap.h escape.h telnet.h getinfo.h \ + strequal.h curl_sec.h memdebug.h http_chunks.h curl_fnmatch.h \ + wildcard.h fileinfo.h ftplistparser.h strtok.h connect.h llist.h \ + hash.h content_encoding.h share.h curl_md4.h curl_md5.h http_digest.h \ + http_negotiate.h inet_pton.h amigaos.h strtoofft.h strerror.h \ + inet_ntop.h curlx.h curl_memory.h curl_setup.h transfer.h select.h \ + easyif.h multiif.h parsedate.h tftp.h sockaddr.h splay.h strdup.h \ + socks.h ssh.h curl_base64.h rawstr.h curl_addrinfo.h curl_sspi.h \ + slist.h nonblock.h curl_memrchr.h imap.h pop3.h smtp.h pingpong.h \ + rtsp.h curl_threads.h warnless.h curl_hmac.h curl_rtmp.h \ + curl_gethostname.h gopher.h http_proxy.h non-ascii.h asyn.h \ + curl_ntlm.h curl_gssapi.h curl_ntlm_wb.h curl_ntlm_core.h \ + curl_ntlm_msgs.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 LIB_RCFILES = libcurl.rc diff --git a/Utilities/cmcurl/lib/amigaos.c b/Utilities/cmcurl/lib/amigaos.c index 34f95e9..e3ff85f 100644 --- a/Utilities/cmcurl/lib/amigaos.c +++ b/Utilities/cmcurl/lib/amigaos.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -71,7 +71,7 @@ bool Curl_amiga_init() } #ifdef __libnix__ -ADD2EXIT(Curl_amiga_cleanup,-50); +ADD2EXIT(Curl_amiga_cleanup, -50); #endif #endif /* __AMIGA__ && ! __ixemul__ */ diff --git a/Utilities/cmcurl/lib/asyn-ares.c b/Utilities/cmcurl/lib/asyn-ares.c index 01a9c9b..98ecdfd 100644 --- a/Utilities/cmcurl/lib/asyn-ares.c +++ b/Utilities/cmcurl/lib/asyn-ares.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -68,9 +68,7 @@ #include "connect.h" #include "select.h" #include "progress.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> +#include "curl_printf.h" # if defined(CURL_STATICLIB) && !defined(CARES_STATICLIB) && \ (defined(WIN32) || defined(_WIN32) || defined(__SYMBIAN32__)) @@ -166,7 +164,7 @@ void Curl_resolver_cleanup(void *resolver) int Curl_resolver_duphandle(void **to, void *from) { /* Clone the ares channel for the new handle */ - if(ARES_SUCCESS != ares_dup((ares_channel*)to,(ares_channel)from)) + if(ARES_SUCCESS != ares_dup((ares_channel*)to, (ares_channel)from)) return CURLE_FAILED_INIT; return CURLE_OK; } @@ -178,7 +176,7 @@ static void destroy_async_data (struct Curl_async *async); */ void Curl_resolver_cancel(struct connectdata *conn) { - if(conn && conn->data && conn->data->state.resolver) + if(conn->data && conn->data->state.resolver) ares_cancel((ares_channel)conn->data->state.resolver); destroy_async_data(&conn->async); } @@ -188,8 +186,7 @@ void Curl_resolver_cancel(struct connectdata *conn) */ static void destroy_async_data (struct Curl_async *async) { - if(async->hostname) - free(async->hostname); + free(async->hostname); if(async->os_specific) { struct ResolverResults *res = (struct ResolverResults *)async->os_specific; @@ -315,7 +312,7 @@ CURLcode Curl_resolver_is_resolved(struct connectdata *conn, struct SessionHandle *data = conn->data; struct ResolverResults *res = (struct ResolverResults *) conn->async.os_specific; - CURLcode rc = CURLE_OK; + CURLcode result = CURLE_OK; *dns = NULL; @@ -329,7 +326,7 @@ CURLcode Curl_resolver_is_resolved(struct connectdata *conn, if(!conn->async.dns) { failf(data, "Could not resolve: %s (%s)", conn->async.hostname, ares_strerror(conn->async.status)); - rc = conn->bits.proxy?CURLE_COULDNT_RESOLVE_PROXY: + result = conn->bits.proxy?CURLE_COULDNT_RESOLVE_PROXY: CURLE_COULDNT_RESOLVE_HOST; } else @@ -338,7 +335,7 @@ CURLcode Curl_resolver_is_resolved(struct connectdata *conn, destroy_async_data(&conn->async); } - return rc; + return result; } /* @@ -355,7 +352,7 @@ CURLcode Curl_resolver_is_resolved(struct connectdata *conn, CURLcode Curl_resolver_wait_resolv(struct connectdata *conn, struct Curl_dns_entry **entry) { - CURLcode rc=CURLE_OK; + CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; long timeout; struct timeval now = Curl_tvnow(); @@ -388,13 +385,13 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn, timeout_ms = 1000; waitperform(conn, timeout_ms); - Curl_resolver_is_resolved(conn,&temp_entry); + Curl_resolver_is_resolved(conn, &temp_entry); if(conn->async.done) break; if(Curl_pgrsUpdate(conn)) { - rc = CURLE_ABORTED_BY_CALLBACK; + result = CURLE_ABORTED_BY_CALLBACK; timeout = -1; /* trigger the cancel below */ } else { @@ -403,6 +400,7 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn, timeout -= timediff?timediff:1; /* always deduct at least 1 */ now = now2; /* for next loop */ } + if(timeout < 0) { /* our timeout, so we cancel the ares operation */ ares_cancel((ares_channel)data->state.resolver); @@ -412,18 +410,17 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn, /* Operation complete, if the lookup was successful we now have the entry in the cache. */ - if(entry) *entry = conn->async.dns; - if(rc) + if(result) /* close the connection, since we can't return failure here without cleaning up this connection properly. TODO: remove this action from here, it is not a name resolver decision. */ connclose(conn, "c-ares resolve failed"); - return rc; + return result; } /* Connects results to the list */ @@ -536,15 +533,15 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, bufp = strdup(hostname); if(bufp) { struct ResolverResults *res = NULL; - Curl_safefree(conn->async.hostname); + free(conn->async.hostname); conn->async.hostname = bufp; conn->async.port = port; conn->async.done = FALSE; /* not done */ conn->async.status = 0; /* clear */ conn->async.dns = NULL; /* clear */ - res = calloc(sizeof(struct ResolverResults),1); + res = calloc(sizeof(struct ResolverResults), 1); if(!res) { - Curl_safefree(conn->async.hostname); + free(conn->async.hostname); conn->async.hostname = NULL; return NULL; } diff --git a/Utilities/cmcurl/lib/asyn-thread.c b/Utilities/cmcurl/lib/asyn-thread.c index e4ad32b..bd47d5a 100644 --- a/Utilities/cmcurl/lib/asyn-thread.c +++ b/Utilities/cmcurl/lib/asyn-thread.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -69,11 +69,9 @@ #include "inet_ntop.h" #include "curl_threads.h" #include "connect.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - +#include "curl_printf.h" #include "curl_memory.h" + /* The last #include file should be: */ #include "memdebug.h" @@ -192,13 +190,12 @@ void destroy_thread_sync_data(struct thread_sync_data * tsd) free(tsd->mtx); } - if(tsd->hostname) - free(tsd->hostname); + free(tsd->hostname); if(tsd->res) Curl_freeaddrinfo(tsd->res); - memset(tsd,0,sizeof(*tsd)); + memset(tsd, 0, sizeof(*tsd)); } /* Initialize resolver thread synchronization data */ @@ -366,9 +363,7 @@ static void destroy_async_data (struct Curl_async *async) } async->os_specific = NULL; - if(async->hostname) - free(async->hostname); - + free(async->hostname); async->hostname = NULL; } @@ -398,7 +393,7 @@ static bool init_resolve_thread (struct connectdata *conn, if(!init_thread_sync_data(td, hostname, port, hints)) goto err_exit; - Curl_safefree(conn->async.hostname); + free(conn->async.hostname); conn->async.hostname = strdup(hostname); if(!conn->async.hostname) goto err_exit; @@ -434,19 +429,21 @@ static bool init_resolve_thread (struct connectdata *conn, static CURLcode resolver_error(struct connectdata *conn) { const char *host_or_proxy; - CURLcode rc; + CURLcode result; + if(conn->bits.httpproxy) { host_or_proxy = "proxy"; - rc = CURLE_COULDNT_RESOLVE_PROXY; + result = CURLE_COULDNT_RESOLVE_PROXY; } else { host_or_proxy = "host"; - rc = CURLE_COULDNT_RESOLVE_HOST; + result = CURLE_COULDNT_RESOLVE_HOST; } failf(conn->data, "Could not resolve %s: %s", host_or_proxy, conn->async.hostname); - return rc; + + return result; } /* @@ -463,13 +460,13 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn, struct Curl_dns_entry **entry) { struct thread_data *td = (struct thread_data*) conn->async.os_specific; - CURLcode rc = CURLE_OK; + CURLcode result = CURLE_OK; DEBUGASSERT(conn && td); /* wait for the thread to resolve the name */ if(Curl_thread_join(&td->thread_hnd)) - rc = getaddrinfo_complete(conn); + result = getaddrinfo_complete(conn); else DEBUGASSERT(0); @@ -480,14 +477,14 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn, if(!conn->async.dns) /* a name was not resolved, report error */ - rc = resolver_error(conn); + result = resolver_error(conn); destroy_async_data(&conn->async); if(!conn->async.dns) connclose(conn, "asynch resolve failed"); - return (rc); + return result; } /* @@ -517,9 +514,9 @@ CURLcode Curl_resolver_is_resolved(struct connectdata *conn, getaddrinfo_complete(conn); if(!conn->async.dns) { - CURLcode rc = resolver_error(conn); + CURLcode result = resolver_error(conn); destroy_async_data(&conn->async); - return rc; + return result; } destroy_async_data(&conn->async); *entry = conn->async.dns; @@ -541,7 +538,7 @@ CURLcode Curl_resolver_is_resolved(struct connectdata *conn, td->poll_interval = 250; td->interval_end = elapsed + td->poll_interval; - Curl_expire_latest(conn->data, td->poll_interval); + Curl_expire(conn->data, td->poll_interval); } return CURLE_OK; @@ -633,7 +630,7 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, } if((pf != PF_INET) && !Curl_ipv6works()) - /* the stack seems to be a non-ipv6 one */ + /* The stack seems to be a non-IPv6 one */ pf = PF_INET; #endif /* CURLRES_IPV6 */ diff --git a/Utilities/cmcurl/lib/base64.c b/Utilities/cmcurl/lib/base64.c index bd9ba35..6b87eed 100644 --- a/Utilities/cmcurl/lib/base64.c +++ b/Utilities/cmcurl/lib/base64.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -23,17 +23,14 @@ /* Base64 encoding/decoding */ #include "curl_setup.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - +#include "curl_printf.h" #include "urldata.h" /* for the SessionHandle definition */ #include "warnless.h" #include "curl_base64.h" -#include "curl_memory.h" #include "non-ascii.h" -/* include memdebug.h last */ +/* The last #include files should be: */ +#include "curl_memory.h" #include "memdebug.h" /* ---- Base64 Encoding/Decoding Table --- */ @@ -49,10 +46,10 @@ static size_t decodeQuantum(unsigned char *dest, const char *src) { size_t padding = 0; const char *s, *p; - unsigned long i, v, x = 0; + unsigned long i, x = 0; for(i = 0, s = src; i < 4; i++, s++) { - v = 0; + unsigned long v = 0; if(*s == '=') { x = (x << 6); @@ -107,7 +104,6 @@ CURLcode Curl_base64_decode(const char *src, size_t length = 0; size_t padding = 0; size_t i; - size_t result; size_t numQuantums; size_t rawlen = 0; unsigned char *pos; @@ -151,9 +147,9 @@ CURLcode Curl_base64_decode(const char *src, /* Decode the quantums */ for(i = 0; i < numQuantums; i++) { - result = decodeQuantum(pos, src); + size_t result = decodeQuantum(pos, src); if(!result) { - Curl_safefree(newstr); + free(newstr); return CURLE_BAD_CONTENT_ENCODING; } @@ -256,8 +252,7 @@ static CURLcode base64_encode(const char *table64, *output = '\0'; *outptr = base64data; /* return pointer to new data, allocated memory */ - if(convbuf) - free(convbuf); + free(convbuf); *outlen = strlen(base64data); /* return the length of the new data */ diff --git a/Utilities/cmcurl/lib/bundles.c b/Utilities/cmcurl/lib/bundles.c deleted file mode 100644 index aadf026..0000000 --- a/Utilities/cmcurl/lib/bundles.c +++ /dev/null @@ -1,110 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 2012, Linus Nielsen Feltzing, <linus@haxx.se> - * Copyright (C) 2012, Daniel Stenberg, <daniel@haxx.se>, et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at http://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 <curl/curl.h> - -#include "urldata.h" -#include "url.h" -#include "progress.h" -#include "multiif.h" -#include "bundles.h" -#include "sendf.h" -#include "rawstr.h" - -#include "curl_memory.h" -/* The last #include file should be: */ -#include "memdebug.h" - -static void conn_llist_dtor(void *user, void *element) -{ - struct connectdata *data = element; - (void)user; - - data->bundle = NULL; -} - -CURLcode Curl_bundle_create(struct SessionHandle *data, - struct connectbundle **cb_ptr) -{ - (void)data; - DEBUGASSERT(*cb_ptr == NULL); - *cb_ptr = malloc(sizeof(struct connectbundle)); - if(!*cb_ptr) - return CURLE_OUT_OF_MEMORY; - - (*cb_ptr)->num_connections = 0; - (*cb_ptr)->server_supports_pipelining = FALSE; - - (*cb_ptr)->conn_list = Curl_llist_alloc((curl_llist_dtor) conn_llist_dtor); - if(!(*cb_ptr)->conn_list) { - Curl_safefree(*cb_ptr); - return CURLE_OUT_OF_MEMORY; - } - return CURLE_OK; -} - -void Curl_bundle_destroy(struct connectbundle *cb_ptr) -{ - if(!cb_ptr) - return; - - if(cb_ptr->conn_list) { - Curl_llist_destroy(cb_ptr->conn_list, NULL); - cb_ptr->conn_list = NULL; - } - Curl_safefree(cb_ptr); -} - -/* Add a connection to a bundle */ -CURLcode Curl_bundle_add_conn(struct connectbundle *cb_ptr, - struct connectdata *conn) -{ - if(!Curl_llist_insert_next(cb_ptr->conn_list, cb_ptr->conn_list->tail, conn)) - return CURLE_OUT_OF_MEMORY; - - conn->bundle = cb_ptr; - - cb_ptr->num_connections++; - return CURLE_OK; -} - -/* Remove a connection from a bundle */ -int Curl_bundle_remove_conn(struct connectbundle *cb_ptr, - struct connectdata *conn) -{ - struct curl_llist_element *curr; - - curr = cb_ptr->conn_list->head; - while(curr) { - if(curr->ptr == conn) { - Curl_llist_remove(cb_ptr->conn_list, curr, NULL); - cb_ptr->num_connections--; - conn->bundle = NULL; - return 1; /* we removed a handle */ - } - curr = curr->next; - } - return 0; -} diff --git a/Utilities/cmcurl/lib/conncache.c b/Utilities/cmcurl/lib/conncache.c index 5bbcf3c..c712ed7 100644 --- a/Utilities/cmcurl/lib/conncache.c +++ b/Utilities/cmcurl/lib/conncache.c @@ -6,7 +6,7 @@ * \___|\___/|_| \_\_____| * * Copyright (C) 2012, Linus Nielsen Feltzing, <linus@haxx.se> - * Copyright (C) 2012 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2012 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -31,66 +31,134 @@ #include "multiif.h" #include "sendf.h" #include "rawstr.h" -#include "bundles.h" #include "conncache.h" +#include "curl_printf.h" #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" -static void free_bundle_hash_entry(void *freethis) +static void conn_llist_dtor(void *user, void *element) { - struct connectbundle *b = (struct connectbundle *) freethis; + struct connectdata *data = element; + (void)user; - Curl_bundle_destroy(b); + data->bundle = NULL; } -struct conncache *Curl_conncache_init(int size) +static CURLcode bundle_create(struct SessionHandle *data, + struct connectbundle **cb_ptr) { - struct conncache *connc; - - connc = calloc(1, sizeof(struct conncache)); - if(!connc) - return NULL; + (void)data; + DEBUGASSERT(*cb_ptr == NULL); + *cb_ptr = malloc(sizeof(struct connectbundle)); + if(!*cb_ptr) + return CURLE_OUT_OF_MEMORY; + + (*cb_ptr)->num_connections = 0; + (*cb_ptr)->multiuse = BUNDLE_UNKNOWN; + + (*cb_ptr)->conn_list = Curl_llist_alloc((curl_llist_dtor) conn_llist_dtor); + if(!(*cb_ptr)->conn_list) { + Curl_safefree(*cb_ptr); + return CURLE_OUT_OF_MEMORY; + } + return CURLE_OK; +} - connc->hash = Curl_hash_alloc(size, Curl_hash_str, - Curl_str_key_compare, free_bundle_hash_entry); +static void bundle_destroy(struct connectbundle *cb_ptr) +{ + if(!cb_ptr) + return; - if(!connc->hash) { - free(connc); - return NULL; + if(cb_ptr->conn_list) { + Curl_llist_destroy(cb_ptr->conn_list, NULL); + cb_ptr->conn_list = NULL; } + free(cb_ptr); +} + +/* Add a connection to a bundle */ +static CURLcode bundle_add_conn(struct connectbundle *cb_ptr, + struct connectdata *conn) +{ + if(!Curl_llist_insert_next(cb_ptr->conn_list, cb_ptr->conn_list->tail, conn)) + return CURLE_OUT_OF_MEMORY; + + conn->bundle = cb_ptr; - return connc; + cb_ptr->num_connections++; + return CURLE_OK; } -void Curl_conncache_destroy(struct conncache *connc) +/* Remove a connection from a bundle */ +static int bundle_remove_conn(struct connectbundle *cb_ptr, + struct connectdata *conn) { - if(connc) { - Curl_hash_destroy(connc->hash); - connc->hash = NULL; - free(connc); + struct curl_llist_element *curr; + + curr = cb_ptr->conn_list->head; + while(curr) { + if(curr->ptr == conn) { + Curl_llist_remove(cb_ptr->conn_list, curr, NULL); + cb_ptr->num_connections--; + conn->bundle = NULL; + return 1; /* we removed a handle */ + } + curr = curr->next; } + return 0; } -struct connectbundle *Curl_conncache_find_bundle(struct conncache *connc, - char *hostname) +static void free_bundle_hash_entry(void *freethis) { - struct connectbundle *bundle = NULL; + struct connectbundle *b = (struct connectbundle *) freethis; + + bundle_destroy(b); +} +int Curl_conncache_init(struct conncache *connc, int size) +{ + return Curl_hash_init(&connc->hash, size, Curl_hash_str, + Curl_str_key_compare, free_bundle_hash_entry); +} + +void Curl_conncache_destroy(struct conncache *connc) +{ if(connc) - bundle = Curl_hash_pick(connc->hash, hostname, strlen(hostname)+1); + Curl_hash_destroy(&connc->hash); +} + +/* returns an allocated key to find a bundle for this connection */ +static char *hashkey(struct connectdata *conn) +{ + return aprintf("%s:%d", + conn->bits.proxy?conn->proxy.name:conn->host.name, + conn->localport); +} + +/* Look up the bundle with all the connections to the same host this + connectdata struct is setup to use. */ +struct connectbundle *Curl_conncache_find_bundle(struct connectdata *conn, + struct conncache *connc) +{ + struct connectbundle *bundle = NULL; + if(connc) { + char *key = hashkey(conn); + if(key) { + bundle = Curl_hash_pick(&connc->hash, key, strlen(key)); + free(key); + } + } return bundle; } static bool conncache_add_bundle(struct conncache *connc, - char *hostname, + char *key, struct connectbundle *bundle) { - void *p; - - p = Curl_hash_add(connc->hash, hostname, strlen(hostname)+1, bundle); + void *p = Curl_hash_add(&connc->hash, key, strlen(key), bundle); return p?TRUE:FALSE; } @@ -104,14 +172,14 @@ static void conncache_remove_bundle(struct conncache *connc, if(!connc) return; - Curl_hash_start_iterate(connc->hash, &iter); + Curl_hash_start_iterate(&connc->hash, &iter); he = Curl_hash_next_element(&iter); while(he) { if(he->ptr == bundle) { /* The bundle is destroyed by the hash destructor function, free_bundle_hash_entry() */ - Curl_hash_delete(connc->hash, he->key, he->key_len); + Curl_hash_delete(&connc->hash, he->key, he->key_len); return; } @@ -127,23 +195,32 @@ CURLcode Curl_conncache_add_conn(struct conncache *connc, struct connectbundle *new_bundle = NULL; struct SessionHandle *data = conn->data; - bundle = Curl_conncache_find_bundle(data->state.conn_cache, - conn->host.name); + bundle = Curl_conncache_find_bundle(conn, data->state.conn_cache); if(!bundle) { - result = Curl_bundle_create(data, &new_bundle); - if(result != CURLE_OK) + char *key; + int rc; + + result = bundle_create(data, &new_bundle); + if(result) return result; - if(!conncache_add_bundle(data->state.conn_cache, - conn->host.name, new_bundle)) { - Curl_bundle_destroy(new_bundle); + key = hashkey(conn); + if(!key) { + bundle_destroy(new_bundle); + return CURLE_OUT_OF_MEMORY; + } + + rc = conncache_add_bundle(data->state.conn_cache, key, new_bundle); + free(key); + if(!rc) { + bundle_destroy(new_bundle); return CURLE_OUT_OF_MEMORY; } bundle = new_bundle; } - result = Curl_bundle_add_conn(bundle, conn); - if(result != CURLE_OK) { + result = bundle_add_conn(bundle, conn); + if(result) { if(new_bundle) conncache_remove_bundle(data->state.conn_cache, new_bundle); return result; @@ -152,6 +229,10 @@ CURLcode Curl_conncache_add_conn(struct conncache *connc, conn->connection_id = connc->next_connection_id++; connc->num_connections++; + DEBUGF(infof(conn->data, "Added connection %ld. " + "The cache now contains %" CURL_FORMAT_CURL_OFF_TU " members\n", + conn->connection_id, (curl_off_t) connc->num_connections)); + return CURLE_OK; } @@ -163,7 +244,7 @@ void Curl_conncache_remove_conn(struct conncache *connc, /* The bundle pointer can be NULL, since this function can be called due to a failed connection attempt, before being added to a bundle */ if(bundle) { - Curl_bundle_remove_conn(bundle, conn); + bundle_remove_conn(bundle, conn); if(bundle->num_connections == 0) { conncache_remove_bundle(connc, bundle); } @@ -171,8 +252,9 @@ void Curl_conncache_remove_conn(struct conncache *connc, if(connc) { connc->num_connections--; - DEBUGF(infof(conn->data, "The cache now contains %d members\n", - connc->num_connections)); + DEBUGF(infof(conn->data, "The cache now contains %" + CURL_FORMAT_CURL_OFF_TU " members\n", + (curl_off_t) connc->num_connections)); } } } @@ -194,12 +276,11 @@ void Curl_conncache_foreach(struct conncache *connc, if(!connc) return; - Curl_hash_start_iterate(connc->hash, &iter); + Curl_hash_start_iterate(&connc->hash, &iter); he = Curl_hash_next_element(&iter); while(he) { struct connectbundle *bundle; - struct connectdata *conn; bundle = he->ptr; he = Curl_hash_next_element(&iter); @@ -208,7 +289,7 @@ void Curl_conncache_foreach(struct conncache *connc, while(curr) { /* Yes, we need to update curr before calling func(), because func() might decide to remove the connection */ - conn = curr->ptr; + struct connectdata *conn = curr->ptr; curr = curr->next; if(1 == func(conn, param)) @@ -223,14 +304,14 @@ struct connectdata * Curl_conncache_find_first_connection(struct conncache *connc) { struct curl_hash_iterator iter; - struct curl_llist_element *curr; struct curl_hash_element *he; struct connectbundle *bundle; - Curl_hash_start_iterate(connc->hash, &iter); + Curl_hash_start_iterate(&connc->hash, &iter); he = Curl_hash_next_element(&iter); while(he) { + struct curl_llist_element *curr; bundle = he->ptr; curr = bundle->conn_list->head; diff --git a/Utilities/cmcurl/lib/conncache.h b/Utilities/cmcurl/lib/conncache.h index d793f24..59181bf 100644 --- a/Utilities/cmcurl/lib/conncache.h +++ b/Utilities/cmcurl/lib/conncache.h @@ -7,6 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * + * Copyright (C) 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * Copyright (C) 2012 - 2014, Linus Nielsen Feltzing, <linus@haxx.se> * * This software is licensed as described in the file COPYING, which @@ -23,18 +24,30 @@ ***************************************************************************/ struct conncache { - struct curl_hash *hash; + struct curl_hash hash; size_t num_connections; long next_connection_id; struct timeval last_cleanup; }; -struct conncache *Curl_conncache_init(int size); +#define BUNDLE_NO_MULTIUSE -1 +#define BUNDLE_UNKNOWN 0 /* initial value */ +#define BUNDLE_PIPELINING 1 +#define BUNDLE_MULTIPLEX 2 + +struct connectbundle { + int multiuse; /* supports multi-use */ + size_t num_connections; /* Number of connections in the bundle */ + struct curl_llist *conn_list; /* The connectdata members of the bundle */ +}; + +int Curl_conncache_init(struct conncache *, int size); void Curl_conncache_destroy(struct conncache *connc); -struct connectbundle *Curl_conncache_find_bundle(struct conncache *connc, - char *hostname); +/* return the correct bundle, to a host or a proxy */ +struct connectbundle *Curl_conncache_find_bundle(struct connectdata *conn, + struct conncache *connc); CURLcode Curl_conncache_add_conn(struct conncache *connc, struct connectdata *conn); diff --git a/Utilities/cmcurl/lib/connect.c b/Utilities/cmcurl/lib/connect.c index fb315fc..18ac32c 100644 --- a/Utilities/cmcurl/lib/connect.c +++ b/Utilities/cmcurl/lib/connect.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -56,15 +56,12 @@ #include <inet.h> #endif -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - +#include "curl_printf.h" #include "urldata.h" #include "sendf.h" #include "if2ip.h" #include "strerror.h" #include "connect.h" -#include "curl_memory.h" #include "select.h" #include "url.h" /* for Curl_safefree() */ #include "multiif.h" @@ -77,7 +74,8 @@ #include "conncache.h" #include "multihandle.h" -/* The last #include file should be: */ +/* The last #include files should be: */ +#include "curl_memory.h" #include "memdebug.h" #ifdef __SYMBIAN32__ @@ -238,7 +236,7 @@ long Curl_timeleft(struct SessionHandle *data, } static CURLcode bindlocal(struct connectdata *conn, - curl_socket_t sockfd, int af) + curl_socket_t sockfd, int af, unsigned int scope) { struct SessionHandle *data = conn->data; @@ -257,12 +255,6 @@ static CURLcode bindlocal(struct connectdata *conn, int portnum = data->set.localportrange; const char *dev = data->set.str[STRING_DEVICE]; int error; - char myhost[256] = ""; - int done = 0; /* -1 for error, 1 for address found */ - bool is_interface = FALSE; - bool is_host = FALSE; - static const char *if_prefix = "if!"; - static const char *host_prefix = "host!"; /************************************************************* * Select device to bind socket to @@ -274,6 +266,13 @@ static CURLcode bindlocal(struct connectdata *conn, memset(&sa, 0, sizeof(struct Curl_sockaddr_storage)); if(dev && (strlen(dev)<255) ) { + char myhost[256] = ""; + int done = 0; /* -1 for error, 1 for address found */ + bool is_interface = FALSE; + bool is_host = FALSE; + static const char *if_prefix = "if!"; + static const char *host_prefix = "host!"; + if(strncmp(if_prefix, dev, strlen(if_prefix)) == 0) { dev += strlen(if_prefix); is_interface = TRUE; @@ -285,7 +284,8 @@ static CURLcode bindlocal(struct connectdata *conn, /* interface */ if(!is_host) { - switch(Curl_if2ip(af, conn->scope, dev, myhost, sizeof(myhost))) { + switch(Curl_if2ip(af, scope, conn->scope_id, dev, + myhost, sizeof(myhost))) { case IF2IP_NOT_FOUND: if(is_interface) { /* Do not fall back to treating it as a host name */ @@ -374,7 +374,7 @@ static CURLcode bindlocal(struct connectdata *conn, if(done > 0) { #ifdef ENABLE_IPV6 - /* ipv6 address */ + /* IPv6 address */ if(af == AF_INET6) { #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID char *scope_ptr = strchr(myhost, '%'); @@ -397,7 +397,7 @@ static CURLcode bindlocal(struct connectdata *conn, } else #endif - /* ipv4 address */ + /* IPv4 address */ if((af == AF_INET) && (Curl_inet_pton(AF_INET, myhost, &si4->sin_addr) > 0)) { si4->sin_family = AF_INET; @@ -540,7 +540,8 @@ static CURLcode trynextip(struct connectdata *conn, int sockindex, int tempindex) { - CURLcode rc = CURLE_COULDNT_CONNECT; + const int other = tempindex ^ 1; + CURLcode result = CURLE_COULDNT_CONNECT; /* First clean up after the failed socket. Don't close it yet to ensure that the next IP's socket gets a different @@ -558,27 +559,29 @@ static CURLcode trynextip(struct connectdata *conn, family = conn->tempaddr[tempindex]->ai_family; ai = conn->tempaddr[tempindex]->ai_next; } +#ifdef ENABLE_IPV6 else if(conn->tempaddr[0]) { /* happy eyeballs - try the other protocol family */ int firstfamily = conn->tempaddr[0]->ai_family; -#ifdef ENABLE_IPV6 family = (firstfamily == AF_INET) ? AF_INET6 : AF_INET; -#else - family = firstfamily; -#endif ai = conn->tempaddr[0]->ai_next; } +#endif while(ai) { - while(ai && ai->ai_family != family) - ai = ai->ai_next; + if(conn->tempaddr[other]) { + /* we can safely skip addresses of the other protocol family */ + while(ai && ai->ai_family != family) + ai = ai->ai_next; + } if(ai) { - rc = singleipconnect(conn, ai, &conn->tempsock[tempindex]); - if(rc == CURLE_COULDNT_CONNECT) { + result = singleipconnect(conn, ai, &conn->tempsock[tempindex]); + if(result == CURLE_COULDNT_CONNECT) { ai = ai->ai_next; continue; } + conn->tempaddr[tempindex] = ai; } break; @@ -588,7 +591,7 @@ static CURLcode trynextip(struct connectdata *conn, if(fd_to_close != CURL_SOCKET_BAD) Curl_closesocket(conn, fd_to_close); - return rc; + return result; } /* Copies connection info into the session handle to make it available @@ -656,7 +659,6 @@ static bool getaddressinfo(struct sockaddr* sa, char* addr, connection */ void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd) { - int error; curl_socklen_t len; struct Curl_sockaddr_storage ssrem; struct Curl_sockaddr_storage ssloc; @@ -667,6 +669,7 @@ void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd) return; if(!conn->bits.reuse) { + int error; len = sizeof(struct Curl_sockaddr_storage); if(getpeername(sockfd, (struct sockaddr*) &ssrem, &len)) { @@ -677,6 +680,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; failf(data, "getsockname() failed with errno %d: %s", @@ -716,11 +720,11 @@ CURLcode Curl_is_connected(struct connectdata *conn, bool *connected) { struct SessionHandle *data = conn->data; - CURLcode code = CURLE_OK; + CURLcode result = CURLE_OK; long allow; int error = 0; struct timeval now; - int result; + int rc; int i; DEBUGASSERT(sockindex >= FIRSTSOCKET && sockindex <= SECONDARYSOCKET); @@ -745,6 +749,7 @@ CURLcode Curl_is_connected(struct connectdata *conn, } for(i=0; i<2; i++) { + const int other = i ^ 1; if(conn->tempsock[i] == CURL_SOCKET_BAD) continue; @@ -756,9 +761,9 @@ CURLcode Curl_is_connected(struct connectdata *conn, #endif /* check socket for connect */ - result = Curl_socket_ready(CURL_SOCKET_BAD, conn->tempsock[i], 0); + rc = Curl_socket_ready(CURL_SOCKET_BAD, conn->tempsock[i], 0); - if(result == 0) { /* no connection yet */ + if(rc == 0) { /* no connection yet */ if(curlx_tvdiff(now, conn->connecttime) >= conn->timeoutms_per_addr) { infof(data, "After %ldms connect time, move on!\n", conn->timeoutms_per_addr); @@ -771,10 +776,9 @@ CURLcode Curl_is_connected(struct connectdata *conn, trynextip(conn, sockindex, 1); } } - else if(result == CURL_CSELECT_OUT) { + else if(rc == CURL_CSELECT_OUT) { if(verifyconnect(conn->tempsock[i], &error)) { /* we are connected with TCP, awesome! */ - int other = i ^ 1; /* use this socket from now on */ conn->sock[sockindex] = conn->tempsock[i]; @@ -788,9 +792,9 @@ CURLcode Curl_is_connected(struct connectdata *conn, } /* see if we need to do any proxy magic first once we connected */ - code = Curl_connected_proxy(conn, sockindex); - if(code) - return code; + result = Curl_connected_proxy(conn, sockindex); + if(result) + return result; conn->bits.tcpconnect[sockindex] = TRUE; @@ -805,7 +809,7 @@ CURLcode Curl_is_connected(struct connectdata *conn, else infof(data, "Connection failed\n"); } - else if(result & CURL_CSELECT_ERR) + else if(rc & CURL_CSELECT_ERR) (void)verifyconnect(conn->tempsock[i], &error); /* @@ -813,10 +817,11 @@ CURLcode Curl_is_connected(struct connectdata *conn, * address" for the given host. But first remember the latest error. */ if(error) { - char ipaddress[MAX_IPADR_LEN]; data->state.os_errno = error; SET_SOCKERRNO(error); if(conn->tempaddr[i]) { + CURLcode status; + char ipaddress[MAX_IPADR_LEN]; Curl_printable_address(conn->tempaddr[i], ipaddress, MAX_IPADR_LEN); infof(data, "connect to %s port %ld failed: %s\n", ipaddress, conn->port, Curl_strerror(conn, error)); @@ -824,21 +829,24 @@ CURLcode Curl_is_connected(struct connectdata *conn, conn->timeoutms_per_addr = conn->tempaddr[i]->ai_next == NULL ? allow : allow / 2; - code = trynextip(conn, sockindex, i); + status = trynextip(conn, sockindex, i); + if(status != CURLE_COULDNT_CONNECT + || conn->tempsock[other] == CURL_SOCKET_BAD) + /* the last attempt failed and no other sockets remain open */ + result = status; } } } - if(code) { + if(result) { /* no more addresses to try */ /* if the first address family runs out of addresses to try before the happy eyeball timeout, go ahead and try the next family now */ if(conn->tempaddr[1] == NULL) { - int rc; - rc = trynextip(conn, sockindex, 1); - if(rc == CURLE_OK) - return CURLE_OK; + result = trynextip(conn, sockindex, 1); + if(!result) + return result; } failf(data, "Failed to connect to %s port %ld: %s", @@ -846,7 +854,7 @@ CURLcode Curl_is_connected(struct connectdata *conn, conn->port, Curl_strerror(conn, error)); } - return code; + return result; } static void tcpnodelay(struct connectdata *conn, @@ -875,7 +883,7 @@ static void tcpnodelay(struct connectdata *conn, infof(data, "Could not set TCP_NODELAY: %s\n", Curl_strerror(conn, SOCKERRNO)); else - infof(data,"TCP_NODELAY set\n"); + infof(data, "TCP_NODELAY set\n"); #else (void)conn; (void)sockfd; @@ -941,16 +949,21 @@ void Curl_sndbufset(curl_socket_t sockfd) detectOsState = DETECT_OS_VISTA_OR_LATER; } #else - ULONGLONG majorVersionMask; + ULONGLONG cm; OSVERSIONINFOEX osver; memset(&osver, 0, sizeof(osver)); osver.dwOSVersionInfoSize = sizeof(osver); osver.dwMajorVersion = majorVersion; - majorVersionMask = VerSetConditionMask(0, VER_MAJORVERSION, - VER_GREATER_EQUAL); - if(VerifyVersionInfo(&osver, VER_MAJORVERSION, majorVersionMask)) + cm = VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL); + cm = VerSetConditionMask(cm, VER_MINORVERSION, VER_GREATER_EQUAL); + cm = VerSetConditionMask(cm, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL); + cm = VerSetConditionMask(cm, VER_SERVICEPACKMINOR, VER_GREATER_EQUAL); + + if(VerifyVersionInfo(&osver, (VER_MAJORVERSION | VER_MINORVERSION | + VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR), + cm)) detectOsState = DETECT_OS_VISTA_OR_LATER; else detectOsState = DETECT_OS_PREVISTA; @@ -977,10 +990,9 @@ void Curl_sndbufset(curl_socket_t sockfd) * singleipconnect() connects to the given IP only, and it may return without * having connected. */ -static CURLcode -singleipconnect(struct connectdata *conn, - const Curl_addrinfo *ai, - curl_socket_t *sockp) +static CURLcode singleipconnect(struct connectdata *conn, + const Curl_addrinfo *ai, + curl_socket_t *sockp) { struct Curl_sockaddr_ex addr; int rc; @@ -988,14 +1000,15 @@ singleipconnect(struct connectdata *conn, bool isconnected = FALSE; struct SessionHandle *data = conn->data; curl_socket_t sockfd; - CURLcode res = CURLE_OK; + CURLcode result; char ipaddress[MAX_IPADR_LEN]; long port; + bool is_tcp; *sockp = CURL_SOCKET_BAD; - res = Curl_socket(conn, ai, &addr, &sockfd); - if(res) + result = Curl_socket(conn, ai, &addr, &sockfd); + if(result) /* Failed to create the socket, but still return OK since we signal the lack of socket as well. This allows the parent function to keep looping over alternative addresses/socket families etc. */ @@ -1013,14 +1026,20 @@ singleipconnect(struct connectdata *conn, } infof(data, " Trying %s...\n", ipaddress); - if(data->set.tcp_nodelay) +#ifdef ENABLE_IPV6 + is_tcp = (addr.family == AF_INET || addr.family == AF_INET6) && + addr.socktype == SOCK_STREAM; +#else + is_tcp = (addr.family == AF_INET) && addr.socktype == SOCK_STREAM; +#endif + if(is_tcp && data->set.tcp_nodelay) tcpnodelay(conn, sockfd); nosigpipe(conn, sockfd); Curl_sndbufset(sockfd); - if(data->set.tcp_keepalive) + if(is_tcp && data->set.tcp_keepalive) tcpkeepalive(data, sockfd); if(data->set.fsockopt) { @@ -1038,19 +1057,26 @@ singleipconnect(struct connectdata *conn, } /* possibly bind the local end to an IP, interface or port */ - res = bindlocal(conn, sockfd, addr.family); - if(res) { - Curl_closesocket(conn, sockfd); /* close socket and bail out */ - if(res == CURLE_UNSUPPORTED_PROTOCOL) { - /* The address family is not supported on this interface. - We can continue trying addresses */ - return CURLE_OK; + if(addr.family == AF_INET +#ifdef ENABLE_IPV6 + || addr.family == AF_INET6 +#endif + ) { + result = bindlocal(conn, sockfd, addr.family, + Curl_ipv6_scope((struct sockaddr*)&addr.sa_addr)); + if(result) { + Curl_closesocket(conn, sockfd); /* close socket and bail out */ + if(result == CURLE_UNSUPPORTED_PROTOCOL) { + /* The address family is not supported on this interface. + We can continue trying addresses */ + return CURLE_COULDNT_CONNECT; + } + return result; } - return res; } /* set socket non-blocking */ - curlx_nonblock(sockfd, TRUE); + (void)curlx_nonblock(sockfd, TRUE); conn->connecttime = Curl_tvnow(); if(conn->num_addr > 1) @@ -1084,25 +1110,25 @@ singleipconnect(struct connectdata *conn, case EAGAIN: #endif #endif - res = CURLE_OK; + result = CURLE_OK; break; default: /* unknown error, fallthrough and try another address! */ infof(data, "Immediate connect fail for %s: %s\n", - ipaddress, Curl_strerror(conn,error)); + ipaddress, Curl_strerror(conn, error)); data->state.os_errno = error; /* connect failed */ Curl_closesocket(conn, sockfd); - res = CURLE_COULDNT_CONNECT; + result = CURLE_COULDNT_CONNECT; } } - if(!res) + if(!result) *sockp = sockfd; - return res; + return result; } /* @@ -1116,7 +1142,7 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */ { struct SessionHandle *data = conn->data; struct timeval before = Curl_tvnow(); - CURLcode res = CURLE_COULDNT_CONNECT; + CURLcode result = CURLE_COULDNT_CONNECT; long timeout_ms = Curl_timeleft(data, &before, TRUE); @@ -1139,14 +1165,17 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */ /* start connecting to first IP */ while(conn->tempaddr[0]) { - res = singleipconnect(conn, conn->tempaddr[0], &(conn->tempsock[0])); - if(res == CURLE_OK) - break; + result = singleipconnect(conn, conn->tempaddr[0], &(conn->tempsock[0])); + if(!result) + break; conn->tempaddr[0] = conn->tempaddr[0]->ai_next; } - if(conn->tempsock[0] == CURL_SOCKET_BAD) - return res; + if(conn->tempsock[0] == CURL_SOCKET_BAD) { + if(!result) + result = CURLE_COULDNT_CONNECT; + return result; + } data->info.numconnects++; /* to track the number of connections made */ @@ -1181,15 +1210,20 @@ curl_socket_t Curl_getconnectinfo(struct SessionHandle *data, DEBUGASSERT(data); - /* this only works for an easy handle that has been used for - curl_easy_perform()! */ - if(data->state.lastconnect && data->multi_easy) { + /* this works for an easy handle: + * - that has been used for curl_easy_perform() + * - that is associated with a multi handle, and whose connection + * was detached with CURLOPT_CONNECT_ONLY + */ + if(data->state.lastconnect && (data->multi_easy || data->multi)) { struct connectdata *c = data->state.lastconnect; struct connfind find; find.tofind = data->state.lastconnect; find.found = FALSE; - Curl_conncache_foreach(data->multi_easy->conn_cache, &find, conn_is_conn); + Curl_conncache_foreach(data->multi_easy? + &data->multi_easy->conn_cache: + &data->multi->conn_cache, &find, conn_is_conn); if(!find.found) { data->state.lastconnect = NULL; @@ -1240,15 +1274,18 @@ int Curl_closesocket(struct connectdata *conn, accept, then we MUST NOT call the callback but clear the accepted status */ conn->sock_accepted[SECONDARYSOCKET] = FALSE; - else + else { + Curl_multi_closed(conn, sock); return conn->fclosesocket(conn->closesocket_client, sock); + } } - sclose(sock); if(conn) /* tell the multi-socket code about this */ Curl_multi_closed(conn, sock); + sclose(sock); + return 0; } @@ -1312,9 +1349,9 @@ CURLcode Curl_socket(struct connectdata *conn, return CURLE_COULDNT_CONNECT; #if defined(ENABLE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID) - if(conn->scope && (addr->family == AF_INET6)) { + if(conn->scope_id && (addr->family == AF_INET6)) { struct sockaddr_in6 * const sa6 = (void *)&addr->sa_addr; - sa6->sin6_scope_id = conn->scope; + sa6->sin6_scope_id = conn->scope_id; } #endif @@ -1325,16 +1362,22 @@ CURLcode Curl_socket(struct connectdata *conn, #ifdef CURLDEBUG /* * Curl_conncontrol() is used to set the conn->bits.close bit on or off. It - * MUST be called with the connclose() or connclose() macros with a stated + * MUST be called with the connclose() or connkeep() macros with a stated * reason. The reason is only shown in debug builds but helps to figure out * decision paths when connections are or aren't re-used as expected. */ void Curl_conncontrol(struct connectdata *conn, bool closeit, const char *reason) { - infof(conn->data, "Marked for [%s]: %s\n", closeit?"closure":"keep alive", - reason); - conn->bits.close = closeit; /* the only place in the source code that should - assign this bit */ +#if defined(CURL_DISABLE_VERBOSE_STRINGS) + (void) reason; +#endif + if(closeit != conn->bits.close) { + infof(conn->data, "Marked for [%s]: %s\n", closeit?"closure":"keep alive", + reason); + + conn->bits.close = closeit; /* the only place in the source code that + should assign this bit */ + } } #endif diff --git a/Utilities/cmcurl/lib/connect.h b/Utilities/cmcurl/lib/connect.h index 7bc391b..91646c7 100644 --- a/Utilities/cmcurl/lib/connect.h +++ b/Utilities/cmcurl/lib/connect.h @@ -41,7 +41,7 @@ long Curl_timeleft(struct SessionHandle *data, #define DEFAULT_CONNECT_TIMEOUT 300000 /* milliseconds == five minutes */ #define HAPPY_EYEBALLS_TIMEOUT 200 /* milliseconds to wait between - ipv4/ipv6 connection attempts */ + IPv4/IPv6 connection attempts */ /* * Used to extract socket and connectdata struct for the most recent diff --git a/Utilities/cmcurl/lib/cookie.c b/Utilities/cmcurl/lib/cookie.c index 375485f..22730cf 100644 --- a/Utilities/cmcurl/lib/cookie.c +++ b/Utilities/cmcurl/lib/cookie.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -26,14 +26,17 @@ RECEIVING COOKIE INFORMATION ============================ -struct CookieInfo *cookie_init(char *file); +struct CookieInfo *Curl_cookie_init(struct SessionHandle *data, + const char *file, struct CookieInfo *inc, bool newsession); Inits a cookie struct to store data in a local file. This is always called before any cookies are set. -int cookies_set(struct CookieInfo *cookie, char *cookie_line); +struct Cookie *Curl_cookie_add(struct SessionHandle *data, + struct CookieInfo *c, bool httpheader, char *lineptr, + const char *domain, const char *path); - The 'cookie_line' parameter is a full "Set-cookie:" line as + The 'lineptr' parameter is a full "Set-cookie:" line as received from a server. The function need to replace previously stored lines that this new @@ -47,8 +50,8 @@ int cookies_set(struct CookieInfo *cookie, char *cookie_line); SENDING COOKIE INFORMATION ========================== -struct Cookies *cookie_getlist(struct CookieInfo *cookie, - char *host, char *path, bool secure); +struct Cookies *Curl_cookie_getlist(struct CookieInfo *cookie, + char *host, char *path, bool secure); For a given host and path, return a linked list of cookies that the client should send to the server if used now. The secure @@ -81,44 +84,33 @@ Example set of cookies: #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) -#define _MPRINTF_REPLACE -#include <curl/mprintf.h> - +#include "curl_printf.h" #include "urldata.h" #include "cookie.h" #include "strequal.h" #include "strtok.h" #include "sendf.h" #include "slist.h" -#include "curl_memory.h" #include "share.h" #include "strtoofft.h" #include "rawstr.h" #include "curl_memrchr.h" #include "inet_pton.h" -/* The last #include file should be: */ +/* The last #include files should be: */ +#include "curl_memory.h" #include "memdebug.h" static void freecookie(struct Cookie *co) { - if(co->expirestr) - free(co->expirestr); - if(co->domain) - free(co->domain); - if(co->path) - free(co->path); - if(co->spath) - free(co->spath); - if(co->name) - free(co->name); - if(co->value) - free(co->value); - if(co->maxage) - free(co->maxage); - if(co->version) - free(co->version); - + free(co->expirestr); + free(co->domain); + free(co->path); + free(co->spath); + free(co->name); + free(co->value); + free(co->maxage); + free(co->version); free(co); } @@ -233,11 +225,14 @@ static char *sanitize_cookie_path(const char *cookie_path) return NULL; /* some stupid site sends path attribute with '"'. */ + len = strlen(new_path); if(new_path[0] == '\"') { - memmove((void *)new_path, (const void *)(new_path + 1), strlen(new_path)); + memmove((void *)new_path, (const void *)(new_path + 1), len); + len--; } - if(new_path[strlen(new_path) - 1] == '\"') { - new_path[strlen(new_path) - 1] = 0x0; + if(len && (new_path[len - 1] == '\"')) { + new_path[len - 1] = 0x0; + len--; } /* RFC6265 5.2.4 The Path Attribute */ @@ -249,8 +244,7 @@ static char *sanitize_cookie_path(const char *cookie_path) } /* convert /hoge/ to /hoge */ - len = strlen(new_path); - if(1 < len && new_path[len - 1] == '/') { + if(len && new_path[len - 1] == '/') { new_path[len - 1] = 0x0; } @@ -259,6 +253,8 @@ static char *sanitize_cookie_path(const char *cookie_path) /* * Load cookies from all given cookie files (CURLOPT_COOKIEFILE). + * + * NOTE: OOM or cookie parsing failures are ignored. */ void Curl_cookie_loadfiles(struct SessionHandle *data) { @@ -266,10 +262,17 @@ void Curl_cookie_loadfiles(struct SessionHandle *data) if(list) { Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); while(list) { - data->cookies = Curl_cookie_init(data, - list->data, - data->cookies, - data->set.cookiesession); + struct CookieInfo *newcookies = Curl_cookie_init(data, + list->data, + data->cookies, + data->set.cookiesession); + if(!newcookies) + /* Failure may be due to OOM or a bad cookie; both are ignored + * but only the first should be + */ + infof(data, "ignoring failed cookie_init for %s\n", list->data); + else + data->cookies = newcookies; list = list->next; } curl_slist_free_all(data->change.cookielist); /* clean up list */ @@ -286,8 +289,7 @@ void Curl_cookie_loadfiles(struct SessionHandle *data) */ static void strstore(char **str, const char *newstr) { - if(*str) - free(*str); + free(*str); *str = strdup(newstr); } @@ -351,6 +353,8 @@ static bool isip(const char *domain) * Be aware that sometimes we get an IP-only host name, and that might also be * a numerical IPv6 address. * + * Returns NULL on out of memory or invalid cookie. This is suboptimal, + * as they should be treated separately. ***************************************************************************/ struct Cookie * @@ -405,7 +409,7 @@ Curl_cookie_add(struct SessionHandle *data, do { /* we have a <what>=<this> pair or a stand-alone word here */ name[0]=what[0]=0; /* init the buffers */ - if(1 <= sscanf(ptr, "%" MAX_NAME_TXT "[^;\r\n =]=%" + if(1 <= sscanf(ptr, "%" MAX_NAME_TXT "[^;\r\n =] =%" MAX_COOKIE_LINE_TXT "[^;\r\n]", name, what)) { /* Use strstore() below to properly deal with received cookie @@ -820,21 +824,13 @@ Curl_cookie_add(struct SessionHandle *data, /* then free all the old pointers */ free(clist->name); - if(clist->value) - free(clist->value); - if(clist->domain) - free(clist->domain); - if(clist->path) - free(clist->path); - if(clist->spath) - free(clist->spath); - if(clist->expirestr) - free(clist->expirestr); - - if(clist->version) - free(clist->version); - if(clist->maxage) - free(clist->maxage); + free(clist->value); + free(clist->domain); + free(clist->path); + free(clist->spath); + free(clist->expirestr); + free(clist->version); + free(clist->maxage); *clist = *co; /* then store all the new data */ @@ -882,6 +878,7 @@ Curl_cookie_add(struct SessionHandle *data, * * If 'newsession' is TRUE, discard all "session cookies" on read from file. * + * Returns NULL on out of memory. Invalid cookies are ignored. ****************************************************************************/ struct CookieInfo *Curl_cookie_init(struct SessionHandle *data, const char *file, @@ -889,8 +886,9 @@ struct CookieInfo *Curl_cookie_init(struct SessionHandle *data, bool newsession) { struct CookieInfo *c; - FILE *fp; + FILE *fp = NULL; bool fromfile=TRUE; + char *line = NULL; if(NULL == inc) { /* we didn't get a struct, create one */ @@ -898,6 +896,8 @@ struct CookieInfo *Curl_cookie_init(struct SessionHandle *data, if(!c) return NULL; /* failed to get memory */ c->filename = strdup(file?file:"none"); /* copy the name just in case */ + if(!c->filename) + goto fail; /* failed to get memory */ } else { /* we got an already existing one, use that */ @@ -914,7 +914,7 @@ struct CookieInfo *Curl_cookie_init(struct SessionHandle *data, fp = NULL; } else - fp = file?fopen(file, "r"):NULL; + fp = file?fopen(file, FOPEN_READTEXT):NULL; c->newsession = newsession; /* new session? */ @@ -922,25 +922,26 @@ struct CookieInfo *Curl_cookie_init(struct SessionHandle *data, char *lineptr; bool headerline; - char *line = malloc(MAX_COOKIE_LINE); - if(line) { - while(fgets(line, MAX_COOKIE_LINE, fp)) { - if(checkprefix("Set-Cookie:", line)) { - /* This is a cookie line, get it! */ - lineptr=&line[11]; - headerline=TRUE; - } - else { - lineptr=line; - headerline=FALSE; - } - while(*lineptr && ISBLANK(*lineptr)) - lineptr++; - - Curl_cookie_add(data, c, headerline, lineptr, NULL, NULL); + line = malloc(MAX_COOKIE_LINE); + if(!line) + goto fail; + while(fgets(line, MAX_COOKIE_LINE, fp)) { + if(checkprefix("Set-Cookie:", line)) { + /* This is a cookie line, get it! */ + lineptr=&line[11]; + headerline=TRUE; + } + else { + lineptr=line; + headerline=FALSE; } - free(line); /* free the line buffer */ + while(*lineptr && ISBLANK(*lineptr)) + lineptr++; + + Curl_cookie_add(data, c, headerline, lineptr, NULL, NULL); } + free(line); /* free the line buffer */ + if(fromfile) fclose(fp); } @@ -948,6 +949,16 @@ struct CookieInfo *Curl_cookie_init(struct SessionHandle *data, c->running = TRUE; /* now, we're running */ return c; + +fail: + free(line); + if(!inc) + /* Only clean up if we allocated it here, as the original could still be in + * use by a share handle */ + Curl_cookie_cleanup(c); + if(fromfile && fp) + fclose(fp); + return NULL; /* out of memory */ } /* sort this so that the longest path gets before the shorter path */ @@ -1127,16 +1138,14 @@ void Curl_cookie_clearall(struct CookieInfo *cookies) void Curl_cookie_freelist(struct Cookie *co, bool cookiestoo) { struct Cookie *next; - if(co) { - while(co) { - next = co->next; - if(cookiestoo) - freecookie(co); - else - free(co); /* we only free the struct since the "members" are all just - pointed out in the main cookie list! */ - co = next; - } + while(co) { + next = co->next; + if(cookiestoo) + freecookie(co); + else + free(co); /* we only free the struct since the "members" are all just + pointed out in the main cookie list! */ + co = next; } } @@ -1183,23 +1192,14 @@ void Curl_cookie_clearsess(struct CookieInfo *cookies) * * Curl_cookie_cleanup() * - * Free a "cookie object" previous created with cookie_init(). + * Free a "cookie object" previous created with Curl_cookie_init(). * ****************************************************************************/ void Curl_cookie_cleanup(struct CookieInfo *c) { - struct Cookie *co; - struct Cookie *next; if(c) { - if(c->filename) - free(c->filename); - co = c->cookies; - - while(co) { - next = co->next; - freecookie(co); - co = next; - } + free(c->filename); + Curl_cookie_freelist(c->cookies, TRUE); free(c); /* free the base struct as well */ } } @@ -1262,7 +1262,7 @@ static int cookie_output(struct CookieInfo *c, const char *dumphere) use_stdout=TRUE; } else { - out = fopen(dumphere, "w"); + out = fopen(dumphere, FOPEN_WRITETEXT); if(!out) return 1; /* failure */ } @@ -1274,9 +1274,10 @@ static int cookie_output(struct CookieInfo *c, const char *dumphere) "# http://curl.haxx.se/docs/http-cookies.html\n" "# This file was generated by libcurl! Edit at your own risk.\n\n", out); - co = c->cookies; - while(co) { + for(co = c->cookies; co; co = co->next) { + if(!co->domain) + continue; format_ptr = get_netscape_format(co); if(format_ptr == NULL) { fprintf(out, "#\n# Fatal libcurl error\n"); @@ -1286,7 +1287,6 @@ static int cookie_output(struct CookieInfo *c, const char *dumphere) } fprintf(out, "%s\n", format_ptr); free(format_ptr); - co=co->next; } } @@ -1307,10 +1307,9 @@ struct curl_slist *Curl_cookie_list(struct SessionHandle *data) (data->cookies->numcookies == 0)) return NULL; - c = data->cookies->cookies; - - while(c) { - /* fill the list with _all_ the cookies we know */ + for(c = data->cookies->cookies; c; c = c->next) { + if(!c->domain) + continue; line = get_netscape_format(c); if(!line) { curl_slist_free_all(list); @@ -1323,7 +1322,6 @@ struct curl_slist *Curl_cookie_list(struct SessionHandle *data) return NULL; } list = beg; - c = c->next; } return list; diff --git a/Utilities/cmcurl/lib/curl_addrinfo.c b/Utilities/cmcurl/lib/curl_addrinfo.c index 10652c6..6627a6b 100644 --- a/Utilities/cmcurl/lib/curl_addrinfo.c +++ b/Utilities/cmcurl/lib/curl_addrinfo.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -33,6 +33,9 @@ #ifdef HAVE_ARPA_INET_H # include <arpa/inet.h> #endif +#ifdef HAVE_SYS_UN_H +# include <sys/un.h> +#endif #ifdef __VMS # include <in.h> @@ -47,15 +50,12 @@ #include "curl_addrinfo.h" #include "inet_pton.h" #include "warnless.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - +#include "curl_printf.h" #include "curl_memory.h" + /* The last #include file should be: */ #include "memdebug.h" - /* * Curl_freeaddrinfo() * @@ -80,13 +80,8 @@ Curl_freeaddrinfo(Curl_addrinfo *cahead) Curl_addrinfo *ca; for(ca = cahead; ca != NULL; ca = canext) { - - if(ca->ai_addr) - free(ca->ai_addr); - - if(ca->ai_canonname) - free(ca->ai_canonname); - + free(ca->ai_addr); + free(ca->ai_canonname); canext = ca->ai_next; free(ca); @@ -354,7 +349,7 @@ Curl_he2ai(const struct hostent *he, int port) prevai = ai; } - if(result != CURLE_OK) { + if(result) { Curl_freeaddrinfo(firstai); firstai = NULL; } @@ -477,6 +472,42 @@ Curl_addrinfo *Curl_str2addr(char *address, int port) return NULL; /* bad input format */ } +#ifdef USE_UNIX_SOCKETS +/** + * Given a path to a Unix domain socket, return a newly allocated Curl_addrinfo + * struct initialized with this path. + */ +Curl_addrinfo *Curl_unix2addr(const char *path) +{ + Curl_addrinfo *ai; + struct sockaddr_un *sa_un; + size_t path_len; + + ai = calloc(1, sizeof(Curl_addrinfo)); + if(!ai) + return NULL; + if((ai->ai_addr = calloc(1, sizeof(struct sockaddr_un))) == NULL) { + free(ai); + return NULL; + } + /* sun_path must be able to store the NUL-terminated path */ + path_len = strlen(path); + if(path_len >= sizeof(sa_un->sun_path)) { + free(ai->ai_addr); + free(ai); + return NULL; + } + + ai->ai_family = AF_UNIX; + ai->ai_socktype = SOCK_STREAM; /* assume reliable transport for HTTP */ + ai->ai_addrlen = (curl_socklen_t) sizeof(struct sockaddr_un); + sa_un = (void *) ai->ai_addr; + sa_un->sun_family = AF_UNIX; + memcpy(sa_un->sun_path, path, path_len + 1); /* copy NUL byte */ + return ai; +} +#endif + #if defined(CURLDEBUG) && defined(HAVE_FREEADDRINFO) /* * curl_dofreeaddrinfo() diff --git a/Utilities/cmcurl/lib/curl_addrinfo.h b/Utilities/cmcurl/lib/curl_addrinfo.h index 6d2b753..4ef8827 100644 --- a/Utilities/cmcurl/lib/curl_addrinfo.h +++ b/Utilities/cmcurl/lib/curl_addrinfo.h @@ -79,6 +79,10 @@ Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port); Curl_addrinfo *Curl_str2addr(char *dotted, int port); +#ifdef USE_UNIX_SOCKETS +Curl_addrinfo *Curl_unix2addr(const char *path); +#endif + #if defined(CURLDEBUG) && defined(HAVE_FREEADDRINFO) void curl_dofreeaddrinfo(struct addrinfo *freethis, diff --git a/Utilities/cmcurl/lib/curl_config.h.cmake b/Utilities/cmcurl/lib/curl_config.h.cmake index a561c3d..06201ec 100644 --- a/Utilities/cmcurl/lib/curl_config.h.cmake +++ b/Utilities/cmcurl/lib/curl_config.h.cmake @@ -47,7 +47,7 @@ #endif /* Use Windows LDAP implementation */ -#cmakedefine CURL_LDAP_WIN 1 +#cmakedefine USE_WIN32_LDAP 1 /* when not building a shared library */ #cmakedefine CURL_STATICLIB 1 @@ -461,6 +461,9 @@ /* Define to 1 if you have a working POSIX-style strerror_r function. */ #cmakedefine HAVE_POSIX_STRERROR_R 1 +/* Define to 1 if you have the <pthread.h> header file */ +#cmakedefine HAVE_PTHREAD_H 1 + /* Define to 1 if you have the <pwd.h> header file. */ #cmakedefine HAVE_PWD_H 1 @@ -873,6 +876,9 @@ /* Define if you want to enable c-ares support */ #cmakedefine USE_ARES 1 +/* Define if you want to enable POSIX threaded DNS lookup */ +#cmakedefine USE_THREADS_POSIX 1 + /* Define to disable non-blocking sockets. */ #cmakedefine USE_BLOCKING_SOCKETS 1 @@ -897,8 +903,8 @@ /* if OpenSSL is in use */ #cmakedefine USE_OPENSSL 1 -/* if SSL is enabled */ -#cmakedefine USE_SSLEAY 1 +/* if Unix domain sockets are enabled */ +#cmakedefine USE_UNIX_SOCKETS /* to enable SSPI support */ #cmakedefine USE_WINDOWS_SSPI 1 diff --git a/Utilities/cmcurl/lib/curl_des.c b/Utilities/cmcurl/lib/curl_des.c new file mode 100644 index 0000000..42c1df9 --- /dev/null +++ b/Utilities/cmcurl/lib/curl_des.c @@ -0,0 +1,63 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2015, Steve Holme, <steve_holme@hotmail.com>. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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" + +#if defined(USE_NTLM) && (!defined(USE_OPENSSL) || defined(HAVE_BORINGSSL)) + +#include "curl_des.h" + +/* + * Curl_des_set_odd_parity() + * + * This is used to apply odd parity to the given byte array. It is typically + * used by when a cryptography engines doesn't have it's own version. + * + * The function is a port of the Java based oddParity() function over at: + * + * http://davenport.sourceforge.net/ntlm.html + * + * Parameters: + * + * bytes [in/out] - The data whose parity bits are to be adjusted for + * odd parity. + * len [out] - The length of the data. + */ +void Curl_des_set_odd_parity(unsigned char *bytes, size_t len) +{ + size_t i; + + for(i = 0; i < len; i++) { + unsigned char b = bytes[i]; + + bool needs_parity = (((b >> 7) ^ (b >> 6) ^ (b >> 5) ^ + (b >> 4) ^ (b >> 3) ^ (b >> 2) ^ + (b >> 1)) & 0x01) == 0; + + if(needs_parity) + bytes[i] |= 0x01; + else + bytes[i] &= 0xfe; + } +} + +#endif /* USE_NTLM && (!USE_OPENSSL || HAVE_BORINGSSL) */ diff --git a/Utilities/cmcurl/lib/bundles.h b/Utilities/cmcurl/lib/curl_des.h index 3816c40..b855db4 100644 --- a/Utilities/cmcurl/lib/bundles.h +++ b/Utilities/cmcurl/lib/curl_des.h @@ -1,5 +1,5 @@ -#ifndef HEADER_CURL_BUNDLES_H -#define HEADER_CURL_BUNDLES_H +#ifndef HEADER_CURL_DES_H +#define HEADER_CURL_DES_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2012, Linus Nielsen Feltzing, <linus@haxx.se> + * Copyright (C) 2015, Steve Holme, <steve_holme@hotmail.com>. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -22,24 +22,13 @@ * ***************************************************************************/ -struct connectbundle { - bool server_supports_pipelining; /* TRUE if server supports pipelining, - set after first response */ - size_t num_connections; /* Number of connections in the bundle */ - struct curl_llist *conn_list; /* The connectdata members of the bundle */ -}; +#include "curl_setup.h" -CURLcode Curl_bundle_create(struct SessionHandle *data, - struct connectbundle **cb_ptr); +#if defined(USE_NTLM) && (!defined(USE_OPENSSL) || defined(HAVE_BORINGSSL)) -void Curl_bundle_destroy(struct connectbundle *cb_ptr); +/* Applies odd parity to the given byte array */ +void Curl_des_set_odd_parity(unsigned char *bytes, size_t length); -CURLcode Curl_bundle_add_conn(struct connectbundle *cb_ptr, - struct connectdata *conn); - -int Curl_bundle_remove_conn(struct connectbundle *cb_ptr, - struct connectdata *conn); - - -#endif /* HEADER_CURL_BUNDLES_H */ +#endif /* USE_NTLM && (!USE_OPENSSL || HAVE_BORINGSSL) */ +#endif /* HEADER_CURL_DES_H */ diff --git a/Utilities/cmcurl/lib/curl_endian.c b/Utilities/cmcurl/lib/curl_endian.c new file mode 100644 index 0000000..bcd66ed --- /dev/null +++ b/Utilities/cmcurl/lib/curl_endian.c @@ -0,0 +1,236 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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 "curl_endian.h" + +/* + * Curl_read16_le() + * + * This function converts a 16-bit integer from the little endian format, as + * used in the incoming package to whatever endian format we're using + * natively. + * + * Parameters: + * + * buf [in] - A pointer to a 2 byte buffer. + * + * Returns the integer. + */ +unsigned short Curl_read16_le(unsigned char *buf) +{ + return (unsigned short)(((unsigned short)buf[0]) | + ((unsigned short)buf[1] << 8)); +} + +/* + * Curl_read32_le() + * + * This function converts a 32-bit integer from the little endian format, as + * used in the incoming package to whatever endian format we're using + * natively. + * + * Parameters: + * + * buf [in] - A pointer to a 4 byte buffer. + * + * Returns the integer. + */ +unsigned int Curl_read32_le(unsigned char *buf) +{ + return ((unsigned int)buf[0]) | ((unsigned int)buf[1] << 8) | + ((unsigned int)buf[2] << 16) | ((unsigned int)buf[3] << 24); +} + +#if (CURL_SIZEOF_CURL_OFF_T > 4) +/* + * Curl_read64_le() + * + * This function converts a 64-bit integer from the little endian format, as + * used in the incoming package to whatever endian format we're using + * natively. + * + * Parameters: + * + * buf [in] - A pointer to a 8 byte buffer. + * + * Returns the integer. + */ +#if defined(HAVE_LONGLONG) +unsigned long long Curl_read64_le(unsigned char *buf) +{ + return ((unsigned long long)buf[0]) | + ((unsigned long long)buf[1] << 8) | + ((unsigned long long)buf[2] << 16) | + ((unsigned long long)buf[3] << 24) | + ((unsigned long long)buf[4] << 32) | + ((unsigned long long)buf[5] << 40) | + ((unsigned long long)buf[6] << 48) | + ((unsigned long long)buf[7] << 56); +} +#else +unsigned __int64 Curl_read64_le(unsigned char *buf) +{ + return ((unsigned __int64)buf[0]) | ((unsigned __int64)buf[1] << 8) | + ((unsigned __int64)buf[2] << 16) | ((unsigned __int64)buf[3] << 24) | + ((unsigned __int64)buf[4] << 32) | ((unsigned __int64)buf[5] << 40) | + ((unsigned __int64)buf[6] << 48) | ((unsigned __int64)buf[7] << 56); +} +#endif + +#endif /* CURL_SIZEOF_CURL_OFF_T > 4 */ + +/* + * Curl_read16_be() + * + * This function converts a 16-bit integer from the big endian format, as + * used in the incoming package to whatever endian format we're using + * natively. + * + * Parameters: + * + * buf [in] - A pointer to a 2 byte buffer. + * + * Returns the integer. + */ +unsigned short Curl_read16_be(unsigned char *buf) +{ + return (unsigned short)(((unsigned short)buf[0] << 8) | + ((unsigned short)buf[1])); +} + +/* + * Curl_read32_be() + * + * This function converts a 32-bit integer from the big endian format, as + * used in the incoming package to whatever endian format we're using + * natively. + * + * Parameters: + * + * buf [in] - A pointer to a 4 byte buffer. + * + * Returns the integer. + */ +unsigned int Curl_read32_be(unsigned char *buf) +{ + return ((unsigned int)buf[0] << 24) | ((unsigned int)buf[1] << 16) | + ((unsigned int)buf[2] << 8) | ((unsigned int)buf[3]); +} + +#if (CURL_SIZEOF_CURL_OFF_T > 4) +/* + * Curl_read64_be() + * + * This function converts a 64-bit integer from the big endian format, as + * used in the incoming package to whatever endian format we're using + * natively. + * + * Parameters: + * + * buf [in] - A pointer to a 8 byte buffer. + * + * Returns the integer. + */ +#if defined(HAVE_LONGLONG) +unsigned long long Curl_read64_be(unsigned char *buf) +{ + return ((unsigned long long)buf[0] << 56) | + ((unsigned long long)buf[1] << 48) | + ((unsigned long long)buf[2] << 40) | + ((unsigned long long)buf[3] << 32) | + ((unsigned long long)buf[4] << 24) | + ((unsigned long long)buf[5] << 16) | + ((unsigned long long)buf[6] << 8) | + ((unsigned long long)buf[7]); +} +#else +unsigned __int64 Curl_read64_be(unsigned char *buf) +{ + return ((unsigned __int64)buf[0] << 56) | ((unsigned __int64)buf[1] << 48) | + ((unsigned __int64)buf[2] << 40) | ((unsigned __int64)buf[3] << 32) | + ((unsigned __int64)buf[4] << 24) | ((unsigned __int64)buf[5] << 16) | + ((unsigned __int64)buf[6] << 8) | ((unsigned __int64)buf[7]); +} +#endif + +#endif /* CURL_SIZEOF_CURL_OFF_T > 4 */ + +/* + * Curl_write16_le() + * + * This function converts a 16-bit integer from the native endian format, + * to little endian format ready for sending down the wire. + * + * Parameters: + * + * value [in] - The 16-bit integer value. + * buffer [in] - A pointer to the output buffer. + */ +void Curl_write16_le(const short value, unsigned char *buffer) +{ + buffer[0] = (char)(value & 0x00FF); + buffer[1] = (char)((value & 0xFF00) >> 8); +} + +/* + * Curl_write32_le() + * + * This function converts a 32-bit integer from the native endian format, + * to little endian format ready for sending down the wire. + * + * Parameters: + * + * value [in] - The 32-bit integer value. + * buffer [in] - A pointer to the output buffer. + */ +void Curl_write32_le(const int value, unsigned char *buffer) +{ + buffer[0] = (char)(value & 0x000000FF); + buffer[1] = (char)((value & 0x0000FF00) >> 8); + buffer[2] = (char)((value & 0x00FF0000) >> 16); + buffer[3] = (char)((value & 0xFF000000) >> 24); +} + +#if (CURL_SIZEOF_CURL_OFF_T > 4) +/* + * Curl_write64_le() + * + * This function converts a 64-bit integer from the native endian format, + * to little endian format ready for sending down the wire. + * + * Parameters: + * + * value [in] - The 64-bit integer value. + * buffer [in] - A pointer to the output buffer. + */ +#if defined(HAVE_LONGLONG) +void Curl_write64_le(const long long value, unsigned char *buffer) +#else +void Curl_write64_le(const __int64 value, unsigned char *buffer) +#endif +{ + Curl_write32_le((int)value, buffer); + Curl_write32_le((int)(value >> 32), buffer + 4); +} +#endif /* CURL_SIZEOF_CURL_OFF_T > 4 */ diff --git a/Utilities/cmcurl/lib/curl_endian.h b/Utilities/cmcurl/lib/curl_endian.h new file mode 100644 index 0000000..e384279 --- /dev/null +++ b/Utilities/cmcurl/lib/curl_endian.h @@ -0,0 +1,70 @@ +#ifndef HEADER_CURL_ENDIAN_H +#define HEADER_CURL_ENDIAN_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ + +/* Converts a 16-bit integer from little endian */ +unsigned short Curl_read16_le(unsigned char *buf); + +/* Converts a 32-bit integer from little endian */ +unsigned int Curl_read32_le(unsigned char *buf); + +#if (CURL_SIZEOF_CURL_OFF_T > 4) +/* Converts a 64-bit integer from little endian */ +#if defined(HAVE_LONGLONG) +unsigned long long Curl_read64_le(unsigned char *buf); +#else +unsigned __int64 Curl_read64_le(unsigned char *buf); +#endif +#endif + +/* Converts a 16-bit integer from big endian */ +unsigned short Curl_read16_be(unsigned char *buf); + +/* Converts a 32-bit integer from big endian */ +unsigned int Curl_read32_be(unsigned char *buf); + +#if (CURL_SIZEOF_CURL_OFF_T > 4) +/* Converts a 64-bit integer from big endian */ +#if defined(HAVE_LONGLONG) +unsigned long long Curl_read64_be(unsigned char *buf); +#else +unsigned __int64 Curl_read64_be(unsigned char *buf); +#endif +#endif + +/* Converts a 16-bit integer to little endian */ +void Curl_write16_le(const short value, unsigned char *buffer); + +/* Converts a 32-bit integer to little endian */ +void Curl_write32_le(const int value, unsigned char *buffer); + +#if (CURL_SIZEOF_CURL_OFF_T > 4) +/* Converts a 64-bit integer to little endian */ +#if defined(HAVE_LONGLONG) +void Curl_write64_le(const long long value, unsigned char *buffer); +#else +void Curl_write64_le(const __int64 value, unsigned char *buffer); +#endif +#endif + +#endif /* HEADER_CURL_ENDIAN_H */ diff --git a/Utilities/cmcurl/lib/curl_fnmatch.c b/Utilities/cmcurl/lib/curl_fnmatch.c index 63f67b9..1e53918 100644 --- a/Utilities/cmcurl/lib/curl_fnmatch.c +++ b/Utilities/cmcurl/lib/curl_fnmatch.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -23,11 +23,8 @@ #include "curl_setup.h" #include "curl_fnmatch.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - #include "curl_memory.h" + /* The last #include file should be: */ #include "memdebug.h" diff --git a/Utilities/cmcurl/lib/curl_gssapi.c b/Utilities/cmcurl/lib/curl_gssapi.c index 232b3ef..9baece5 100644 --- a/Utilities/cmcurl/lib/curl_gssapi.c +++ b/Utilities/cmcurl/lib/curl_gssapi.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2011 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2011 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -27,9 +27,9 @@ #include "curl_gssapi.h" #include "sendf.h" -static const char spnego_oid_bytes[] = "\x2b\x06\x01\x05\x05\x02"; +static char spnego_oid_bytes[] = "\x2b\x06\x01\x05\x05\x02"; gss_OID_desc Curl_spnego_mech_oid = { 6, &spnego_oid_bytes }; -static const char krb5_oid_bytes[] = "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"; +static char krb5_oid_bytes[] = "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"; gss_OID_desc Curl_krb5_mech_oid = { 9, &krb5_oid_bytes }; OM_uint32 Curl_gss_init_sec_context( @@ -41,9 +41,13 @@ OM_uint32 Curl_gss_init_sec_context( gss_channel_bindings_t input_chan_bindings, gss_buffer_t input_token, gss_buffer_t output_token, + const bool mutual_auth, OM_uint32 *ret_flags) { - OM_uint32 req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG; + OM_uint32 req_flags = GSS_C_REPLAY_FLAG; + + if(mutual_auth) + req_flags |= GSS_C_MUTUAL_FLAG; if(data->set.gssapi_delegation & CURLGSSAPI_DELEGATION_POLICY_FLAG) { #ifdef GSS_C_DELEG_POLICY_FLAG @@ -72,4 +76,45 @@ OM_uint32 Curl_gss_init_sec_context( NULL /* time_rec */); } +/* + * Curl_gss_log_error() + * + * This is used to log a GSS-API error status. + * + * Parameters: + * + * data [in] - The session handle. + * status [in] - The status code. + * prefix [in] - The prefix of the log message. + */ +void Curl_gss_log_error(struct SessionHandle *data, OM_uint32 status, + const char *prefix) +{ + OM_uint32 maj_stat; + OM_uint32 min_stat; + OM_uint32 msg_ctx = 0; + gss_buffer_desc status_string; + char buf[1024]; + size_t len; + + snprintf(buf, sizeof(buf), "%s", prefix); + len = strlen(buf); + do { + maj_stat = gss_display_status(&min_stat, + status, + GSS_C_MECH_CODE, + GSS_C_NO_OID, + &msg_ctx, + &status_string); + if(sizeof(buf) > len + status_string.length + 1) { + snprintf(buf + len, sizeof(buf) - len, + ": %s", (char*)status_string.value); + len += status_string.length; + } + gss_release_buffer(&min_stat, &status_string); + } while(!GSS_ERROR(maj_stat) && msg_ctx != 0); + + infof(data, "%s\n", buf); +} + #endif /* HAVE_GSSAPI */ diff --git a/Utilities/cmcurl/lib/curl_gssapi.h b/Utilities/cmcurl/lib/curl_gssapi.h index b91bd7e..19aab64 100644 --- a/Utilities/cmcurl/lib/curl_gssapi.h +++ b/Utilities/cmcurl/lib/curl_gssapi.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2011 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -43,7 +43,6 @@ extern gss_OID_desc Curl_spnego_mech_oid; extern gss_OID_desc Curl_krb5_mech_oid; /* Common method for using GSS-API */ - OM_uint32 Curl_gss_init_sec_context( struct SessionHandle *data, OM_uint32 *minor_status, @@ -53,8 +52,24 @@ OM_uint32 Curl_gss_init_sec_context( gss_channel_bindings_t input_chan_bindings, gss_buffer_t input_token, gss_buffer_t output_token, + const bool mutual_auth, OM_uint32 *ret_flags); +/* Helper to log a GSS-API error status */ +void Curl_gss_log_error(struct SessionHandle *data, OM_uint32 status, + const char *prefix); + +/* Provide some definitions missing in old headers */ +#ifdef HAVE_OLD_GSSMIT +#define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name +#define NCOMPAT 1 +#endif + +/* Define our privacy and integrity protection values */ +#define GSSAUTH_P_NONE 1 +#define GSSAUTH_P_INTEGRITY 2 +#define GSSAUTH_P_PRIVACY 4 + #endif /* HAVE_GSSAPI */ #endif /* HEADER_CURL_GSSAPI_H */ diff --git a/Utilities/cmcurl/lib/curl_md4.h b/Utilities/cmcurl/lib/curl_md4.h index b0be9cf..13c7903 100644 --- a/Utilities/cmcurl/lib/curl_md4.h +++ b/Utilities/cmcurl/lib/curl_md4.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -24,10 +24,12 @@ #include "curl_setup.h" -/* NSS crypto library does not provide the MD4 hash algorithm, so that we have - * a local implementation of it */ -#ifdef USE_NSS +/* NSS and OS/400 crypto library do not provide the MD4 hash algorithm, so + * that we have a local implementation of it */ +#if defined(USE_NSS) || defined(USE_OS400CRYPTO) + void Curl_md4it(unsigned char *output, const unsigned char *input, size_t len); -#endif /* USE_NSS */ + +#endif /* defined(USE_NSS) || defined(USE_OS400CRYPTO) */ #endif /* HEADER_CURL_MD4_H */ diff --git a/Utilities/cmcurl/lib/curl_memory.h b/Utilities/cmcurl/lib/curl_memory.h index e3cdc72..bc744cc 100644 --- a/Utilities/cmcurl/lib/curl_memory.h +++ b/Utilities/cmcurl/lib/curl_memory.h @@ -28,6 +28,9 @@ * File curl_memory.h must be included by _all_ *.c source files * that use memory related functions strdup, malloc, calloc, realloc * or free, and given source file is used to build libcurl library. + * It should be included immediately before memdebug.h as the last files + * included to avoid undesired interaction with other memory function + * headers in dependent libraries. * * There is nearly no exception to above rule. All libcurl source * files in 'lib' subdirectory as well as those living deep inside diff --git a/Utilities/cmcurl/lib/curl_memrchr.c b/Utilities/cmcurl/lib/curl_memrchr.c index a71c2bb..6722c6a 100644 --- a/Utilities/cmcurl/lib/curl_memrchr.c +++ b/Utilities/cmcurl/lib/curl_memrchr.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -21,13 +21,9 @@ ***************************************************************************/ #include "curl_setup.h" - #include "curl_memrchr.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - #include "curl_memory.h" + /* The last #include file should be: */ #include "memdebug.h" diff --git a/Utilities/cmcurl/lib/curl_multibyte.c b/Utilities/cmcurl/lib/curl_multibyte.c index 6c02239..403d005 100644 --- a/Utilities/cmcurl/lib/curl_multibyte.c +++ b/Utilities/cmcurl/lib/curl_multibyte.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -22,18 +22,16 @@ #include "curl_setup.h" -#if defined(USE_WIN32_IDN) || (defined(USE_WINDOWS_SSPI) && defined(UNICODE)) +#if defined(USE_WIN32_IDN) || ((defined(USE_WINDOWS_SSPI) || \ + defined(USE_WIN32_LDAP)) && defined(UNICODE)) /* * MultiByte conversions using Windows kernel32 library. */ #include "curl_multibyte.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - #include "curl_memory.h" + /* The last #include file should be: */ #include "memdebug.h" @@ -49,7 +47,8 @@ wchar_t *Curl_convert_UTF8_to_wchar(const char *str_utf8) if(str_w) { if(MultiByteToWideChar(CP_UTF8, 0, str_utf8, -1, str_w, str_w_len) == 0) { - Curl_safefree(str_w); + free(str_w); + return NULL; } } } @@ -70,7 +69,8 @@ char *Curl_convert_wchar_to_UTF8(const wchar_t *str_w) if(str_utf8) { if(WideCharToMultiByte(CP_UTF8, 0, str_w, -1, str_utf8, str_utf8_len, NULL, FALSE) == 0) { - Curl_safefree(str_utf8); + free(str_utf8); + return NULL; } } } @@ -79,4 +79,4 @@ char *Curl_convert_wchar_to_UTF8(const wchar_t *str_w) return str_utf8; } -#endif /* USE_WIN32_IDN || (USE_WINDOWS_SSPI && UNICODE) */ +#endif /* USE_WIN32_IDN || ((USE_WINDOWS_SSPI || USE_WIN32_LDAP) && UNICODE) */ diff --git a/Utilities/cmcurl/lib/curl_multibyte.h b/Utilities/cmcurl/lib/curl_multibyte.h index 7ee5eae..dc7ed4c 100644 --- a/Utilities/cmcurl/lib/curl_multibyte.h +++ b/Utilities/cmcurl/lib/curl_multibyte.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -23,7 +23,8 @@ ***************************************************************************/ #include "curl_setup.h" -#if defined(USE_WIN32_IDN) || (defined(USE_WINDOWS_SSPI) && defined(UNICODE)) +#if defined(USE_WIN32_IDN) || ((defined(USE_WINDOWS_SSPI) || \ + defined(USE_WIN32_LDAP)) && defined(UNICODE)) /* * MultiByte conversions using Windows kernel32 library. @@ -32,10 +33,11 @@ wchar_t *Curl_convert_UTF8_to_wchar(const char *str_utf8); char *Curl_convert_wchar_to_UTF8(const wchar_t *str_w); -#endif /* USE_WIN32_IDN || (USE_WINDOWS_SSPI && UNICODE) */ +#endif /* USE_WIN32_IDN || ((USE_WINDOWS_SSPI || USE_WIN32_LDAP) && UNICODE) */ -#if defined(USE_WIN32_IDN) || defined(USE_WINDOWS_SSPI) +#if defined(USE_WIN32_IDN) || defined(USE_WINDOWS_SSPI) || \ + defined(USE_WIN32_LDAP) /* * Macros Curl_convert_UTF8_to_tchar(), Curl_convert_tchar_to_UTF8() @@ -85,6 +87,6 @@ typedef union { #endif /* UNICODE */ -#endif /* USE_WIN32_IDN || USE_WINDOWS_SSPI */ +#endif /* USE_WIN32_IDN || USE_WINDOWS_SSPI || USE_WIN32_LDAP */ #endif /* HEADER_CURL_MULTIBYTE_H */ diff --git a/Utilities/cmcurl/lib/curl_ntlm.c b/Utilities/cmcurl/lib/curl_ntlm.c index 8c02aba..f9ddf50 100644 --- a/Utilities/cmcurl/lib/curl_ntlm.c +++ b/Utilities/cmcurl/lib/curl_ntlm.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -22,7 +22,7 @@ #include "curl_setup.h" -#ifdef USE_NTLM +#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) /* * NTLM details: @@ -39,11 +39,9 @@ #include "curl_ntlm.h" #include "curl_ntlm_msgs.h" #include "curl_ntlm_wb.h" +#include "curl_sasl.h" #include "url.h" -#include "curl_memory.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> +#include "curl_printf.h" #if defined(USE_NSS) #include "vtls/nssg.h" @@ -51,7 +49,8 @@ #include "curl_sspi.h" #endif -/* The last #include file should be: */ +/* The last #include files should be: */ +#include "curl_memory.h" #include "memdebug.h" #if DEBUG_ME @@ -69,12 +68,6 @@ CURLcode Curl_input_ntlm(struct connectdata *conn, struct ntlmdata *ntlm; CURLcode result = CURLE_OK; -#ifdef USE_NSS - result = Curl_nss_force_init(conn->data); - if(result) - return result; -#endif - ntlm = proxy ? &conn->proxyntlm : &conn->ntlm; if(checkprefix("NTLM", header)) { @@ -84,14 +77,18 @@ CURLcode Curl_input_ntlm(struct connectdata *conn, header++; if(*header) { - result = Curl_ntlm_decode_type2_message(conn->data, header, ntlm); - if(CURLE_OK != result) + result = Curl_sasl_decode_ntlm_type2_message(conn->data, header, ntlm); + if(result) return result; ntlm->state = NTLMSTATE_TYPE2; /* We got a type-2 message */ } else { - if(ntlm->state == NTLMSTATE_TYPE3) { + if(ntlm->state == NTLMSTATE_LAST) { + infof(conn->data, "NTLM auth restarted\n"); + Curl_http_ntlm_cleanup(conn); + } + else if(ntlm->state == NTLMSTATE_TYPE3) { infof(conn->data, "NTLM handshake rejected\n"); Curl_http_ntlm_cleanup(conn); ntlm->state = NTLMSTATE_NONE; @@ -112,12 +109,11 @@ CURLcode Curl_input_ntlm(struct connectdata *conn, /* * This is for creating ntlm header output */ -CURLcode Curl_output_ntlm(struct connectdata *conn, - bool proxy) +CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy) { char *base64 = NULL; size_t len = 0; - CURLcode error; + CURLcode result; /* point to the address of the pointer that holds the string to send to the server, which is for a plain host or for a HTTP proxy */ @@ -175,38 +171,40 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, case NTLMSTATE_TYPE1: default: /* for the weird cases we (re)start here */ /* Create a type-1 message */ - error = Curl_ntlm_create_type1_message(userp, passwdp, ntlm, &base64, - &len); - if(error) - return error; + result = Curl_sasl_create_ntlm_type1_message(userp, passwdp, ntlm, &base64, + &len); + if(result) + return result; if(base64) { - Curl_safefree(*allocuserpwd); + free(*allocuserpwd); *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n", proxy ? "Proxy-" : "", base64); free(base64); if(!*allocuserpwd) return CURLE_OUT_OF_MEMORY; + DEBUG_OUT(fprintf(stderr, "**** Header %s\n ", *allocuserpwd)); } break; case NTLMSTATE_TYPE2: /* We already received the type-2 message, create a type-3 message */ - error = Curl_ntlm_create_type3_message(conn->data, userp, passwdp, - ntlm, &base64, &len); - if(error) - return error; + result = Curl_sasl_create_ntlm_type3_message(conn->data, userp, passwdp, + ntlm, &base64, &len); + if(result) + return result; if(base64) { - Curl_safefree(*allocuserpwd); + free(*allocuserpwd); *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n", proxy ? "Proxy-" : "", base64); free(base64); if(!*allocuserpwd) return CURLE_OUT_OF_MEMORY; + DEBUG_OUT(fprintf(stderr, "**** %s\n ", *allocuserpwd)); ntlm->state = NTLMSTATE_TYPE3; /* we send a type-3 */ @@ -217,6 +215,9 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, case NTLMSTATE_TYPE3: /* connection is already authenticated, * don't send a header in future requests */ + ntlm->state = NTLMSTATE_LAST; + + case NTLMSTATE_LAST: Curl_safefree(*allocuserpwd); authp->done = TRUE; break; @@ -227,22 +228,12 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, void Curl_http_ntlm_cleanup(struct connectdata *conn) { -#ifdef USE_WINDOWS_SSPI - Curl_ntlm_sspi_cleanup(&conn->ntlm); - Curl_ntlm_sspi_cleanup(&conn->proxyntlm); -#elif defined(NTLM_WB_ENABLED) - Curl_ntlm_wb_cleanup(conn); -#else - (void)conn; -#endif + Curl_sasl_ntlm_cleanup(&conn->ntlm); + Curl_sasl_ntlm_cleanup(&conn->proxyntlm); -#ifndef USE_WINDOWS_SSPI - Curl_safefree(conn->ntlm.target_info); - conn->ntlm.target_info_len = 0; - - Curl_safefree(conn->proxyntlm.target_info); - conn->proxyntlm.target_info_len = 0; +#if defined(NTLM_WB_ENABLED) + Curl_ntlm_wb_cleanup(conn); #endif } -#endif /* USE_NTLM */ +#endif /* !CURL_DISABLE_HTTP && USE_NTLM */ diff --git a/Utilities/cmcurl/lib/curl_ntlm.h b/Utilities/cmcurl/lib/curl_ntlm.h index 21a9e9e..947eac2 100644 --- a/Utilities/cmcurl/lib/curl_ntlm.h +++ b/Utilities/cmcurl/lib/curl_ntlm.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -24,7 +24,7 @@ #include "curl_setup.h" -#ifdef USE_NTLM +#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) /* this is for ntlm header input */ CURLcode Curl_input_ntlm(struct connectdata *conn, bool proxy, @@ -35,10 +35,6 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy); void Curl_http_ntlm_cleanup(struct connectdata *conn); -#else - -#define Curl_http_ntlm_cleanup(a) Curl_nop_stmt - -#endif +#endif /* !CURL_DISABLE_HTTP && USE_NTLM */ #endif /* HEADER_CURL_NTLM_H */ diff --git a/Utilities/cmcurl/lib/curl_ntlm_core.c b/Utilities/cmcurl/lib/curl_ntlm_core.c index b011626..2e5b573 100644 --- a/Utilities/cmcurl/lib/curl_ntlm_core.c +++ b/Utilities/cmcurl/lib/curl_ntlm_core.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -22,7 +22,7 @@ #include "curl_setup.h" -#if defined(USE_NTLM) && !defined(USE_WINDOWS_SSPI) +#if defined(USE_NTLM) /* * NTLM details: @@ -31,7 +31,9 @@ * http://www.innovation.ch/java/ntlm.html */ -#ifdef USE_SSLEAY +#if !defined(USE_WINDOWS_SSPI) || defined(USE_WIN32_CRYPTO) + +#ifdef USE_OPENSSL # ifdef USE_OPENSSL # include <openssl/des.h> @@ -87,6 +89,11 @@ # include <CommonCrypto/CommonCryptor.h> # include <CommonCrypto/CommonDigest.h> +#elif defined(USE_OS400CRYPTO) +# include "cipher.mih" /* mih/cipher */ +# include "curl_md4.h" +#elif defined(USE_WIN32_CRYPTO) +# include <wincrypt.h> #else # error "Can't compile NTLM support without a crypto library." #endif @@ -94,32 +101,27 @@ #include "urldata.h" #include "non-ascii.h" #include "rawstr.h" -#include "curl_memory.h" #include "curl_ntlm_core.h" #include "curl_md5.h" #include "curl_hmac.h" #include "warnless.h" +#include "curl_endian.h" +#include "curl_des.h" +#include "curl_printf.h" -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - -/* The last #include file should be: */ +/* The last #include files should be: */ +#include "curl_memory.h" #include "memdebug.h" #define NTLM_HMAC_MD5_LEN (16) #define NTLMv2_BLOB_SIGNATURE "\x01\x01\x00\x00" #define NTLMv2_BLOB_LEN (44 -16 + ntlm->target_info_len + 4) -#ifdef USE_SSLEAY /* - * Turns a 56 bit key into the 64 bit, odd parity key and sets the key. The - * key schedule ks is also set. - */ -static void setup_des_key(const unsigned char *key_56, - DES_key_schedule DESKEYARG(ks)) +* Turns a 56-bit key into being 64-bit wide. +*/ +static void extend_key_56_to_64(const unsigned char *key_56, char *key) { - DES_cblock key; - key[0] = key_56[0]; key[1] = (unsigned char)(((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1)); key[2] = (unsigned char)(((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2)); @@ -128,36 +130,47 @@ static void setup_des_key(const unsigned char *key_56, key[5] = (unsigned char)(((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5)); key[6] = (unsigned char)(((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6)); key[7] = (unsigned char) ((key_56[6] << 1) & 0xFF); - - DES_set_odd_parity(&key); - DES_set_key(&key, ks); } -#else /* defined(USE_SSLEAY) */ - +#ifdef USE_OPENSSL /* - * Turns a 56 bit key into the 64 bit, odd parity key. Used by GnuTLS and NSS. + * Turns a 56 bit key into the 64 bit, odd parity key and sets the key. The + * key schedule ks is also set. */ -static void extend_key_56_to_64(const unsigned char *key_56, char *key) +static void setup_des_key(const unsigned char *key_56, + DES_key_schedule DESKEYARG(ks)) { - key[0] = key_56[0]; - key[1] = (unsigned char)(((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1)); - key[2] = (unsigned char)(((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2)); - key[3] = (unsigned char)(((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3)); - key[4] = (unsigned char)(((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4)); - key[5] = (unsigned char)(((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5)); - key[6] = (unsigned char)(((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6)); - key[7] = (unsigned char) ((key_56[6] << 1) & 0xFF); + DES_cblock key; + + /* Expand the 56-bit key to 64-bits */ + extend_key_56_to_64(key_56, (char *) key); + + /* Set the key parity to odd */ +#if defined(HAVE_BORINGSSL) + Curl_des_set_odd_parity((unsigned char *) &key, sizeof(key)); +#else + DES_set_odd_parity(&key); +#endif + + /* Set the key */ + DES_set_key(&key, ks); } -#if defined(USE_GNUTLS_NETTLE) +#elif defined(USE_GNUTLS_NETTLE) static void setup_des_key(const unsigned char *key_56, struct des_ctx *des) { char key[8]; + + /* Expand the 56-bit key to 64-bits */ extend_key_56_to_64(key_56, key); - des_set_key(des, (const uint8_t*)key); + + /* Set the key parity to odd */ + Curl_des_set_odd_parity((unsigned char *) key, sizeof(key)); + + /* Set the key */ + des_set_key(des, (const uint8_t *) key); } #elif defined(USE_GNUTLS) @@ -169,8 +182,15 @@ static void setup_des_key(const unsigned char *key_56, gcry_cipher_hd_t *des) { char key[8]; + + /* Expand the 56-bit key to 64-bits */ extend_key_56_to_64(key_56, key); - gcry_cipher_setkey(*des, key, 8); + + /* Set the key parity to odd */ + Curl_des_set_odd_parity((unsigned char *) key, sizeof(key)); + + /* Set the key */ + gcry_cipher_setkey(*des, key, sizeof(key)); } #elif defined(USE_NSS) @@ -198,16 +218,21 @@ static bool encrypt_des(const unsigned char *in, unsigned char *out, if(!slot) return FALSE; - /* expand the 56 bit key to 64 bit and wrap by NSS */ + /* Expand the 56-bit key to 64-bits */ extend_key_56_to_64(key_56, key); + + /* Set the key parity to odd */ + Curl_des_set_odd_parity((unsigned char *) key, sizeof(key)); + + /* Import the key */ key_item.data = (unsigned char *)key; - key_item.len = /* hard-wired */ 8; + key_item.len = sizeof(key); symkey = PK11_ImportSymKey(slot, mech, PK11_OriginUnwrap, CKA_ENCRYPT, &key_item, NULL); if(!symkey) goto fail; - /* create DES encryption context */ + /* Create the DES encryption context */ param = PK11_ParamFromIV(mech, /* no IV in ECB mode */ NULL); if(!param) goto fail; @@ -215,7 +240,7 @@ static bool encrypt_des(const unsigned char *in, unsigned char *out, if(!ctx) goto fail; - /* perform the encryption */ + /* Perform the encryption */ if(SECSuccess == PK11_CipherOp(ctx, out, &out_len, /* outbuflen */ 8, (unsigned char *)in, /* inbuflen */ 8) && SECSuccess == PK11_Finalize(ctx)) @@ -242,16 +267,95 @@ static bool encrypt_des(const unsigned char *in, unsigned char *out, size_t out_len; CCCryptorStatus err; + /* Expand the 56-bit key to 64-bits */ extend_key_56_to_64(key_56, key); + + /* Set the key parity to odd */ + Curl_des_set_odd_parity((unsigned char *) key, sizeof(key)); + + /* Perform the encryption */ err = CCCrypt(kCCEncrypt, kCCAlgorithmDES, kCCOptionECBMode, key, kCCKeySizeDES, NULL, in, 8 /* inbuflen */, out, 8 /* outbuflen */, &out_len); + return err == kCCSuccess; } -#endif /* defined(USE_DARWINSSL) */ +#elif defined(USE_OS400CRYPTO) -#endif /* defined(USE_SSLEAY) */ +static bool encrypt_des(const unsigned char *in, unsigned char *out, + const unsigned char *key_56) +{ + char key[8]; + _CIPHER_Control_T ctl; + + /* Setup the cipher control structure */ + ctl.Func_ID = ENCRYPT_ONLY; + ctl.Data_Len = sizeof(key); + + /* Expand the 56-bit key to 64-bits */ + extend_key_56_to_64(key_56, ctl.Crypto_Key); + + /* Set the key parity to odd */ + Curl_des_set_odd_parity((unsigned char *) ctl.Crypto_Key, ctl.Data_Len); + + /* Perform the encryption */ + _CIPHER((_SPCPTR *) &out, &ctl, (_SPCPTR *) &in); + + return TRUE; +} + +#elif defined(USE_WIN32_CRYPTO) + +static bool encrypt_des(const unsigned char *in, unsigned char *out, + const unsigned char *key_56) +{ + HCRYPTPROV hprov; + HCRYPTKEY hkey; + struct { + BLOBHEADER hdr; + unsigned int len; + char key[8]; + } blob; + DWORD len = 8; + + /* Acquire the crypto provider */ + if(!CryptAcquireContext(&hprov, NULL, NULL, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT)) + return FALSE; + + /* Setup the key blob structure */ + memset(&blob, 0, sizeof(blob)); + blob.hdr.bType = PLAINTEXTKEYBLOB; + blob.hdr.bVersion = 2; + blob.hdr.aiKeyAlg = CALG_DES; + blob.len = sizeof(blob.key); + + /* Expand the 56-bit key to 64-bits */ + extend_key_56_to_64(key_56, blob.key); + + /* Set the key parity to odd */ + Curl_des_set_odd_parity((unsigned char *) blob.key, sizeof(blob.key)); + + /* Import the key */ + if(!CryptImportKey(hprov, (BYTE *) &blob, sizeof(blob), 0, 0, &hkey)) { + CryptReleaseContext(hprov, 0); + + return FALSE; + } + + memcpy(out, in, 8); + + /* Perform the encryption */ + CryptEncrypt(hkey, 0, FALSE, 0, out, &len, len); + + CryptDestroyKey(hkey); + CryptReleaseContext(hprov, 0); + + return TRUE; +} + +#endif /* defined(USE_WIN32_CRYPTO) */ /* * takes a 21 byte array and treats it as 3 56-bit DES keys. The @@ -262,7 +366,7 @@ void Curl_ntlm_core_lm_resp(const unsigned char *keys, const unsigned char *plaintext, unsigned char *results) { -#ifdef USE_SSLEAY +#ifdef USE_OPENSSL DES_key_schedule ks; setup_des_key(keys, DESKEY(ks)); @@ -301,7 +405,8 @@ 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_NSS) || defined(USE_DARWINSSL) +#elif defined(USE_NSS) || defined(USE_DARWINSSL) || defined(USE_OS400CRYPTO) \ + || defined(USE_WIN32_CRYPTO) encrypt_des(plaintext, results, keys); encrypt_des(plaintext, results + 8, keys + 7); encrypt_des(plaintext, results + 16, keys + 14); @@ -311,11 +416,11 @@ void Curl_ntlm_core_lm_resp(const unsigned char *keys, /* * Set up lanmanager hashed password */ -void Curl_ntlm_core_mk_lm_hash(struct SessionHandle *data, - const char *password, - unsigned char *lmbuffer /* 21 bytes */) +CURLcode Curl_ntlm_core_mk_lm_hash(struct SessionHandle *data, + const char *password, + unsigned char *lmbuffer /* 21 bytes */) { - CURLcode res; + CURLcode result; unsigned char pw[14]; static const unsigned char magic[] = { 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 /* i.e. KGS!@#$% */ @@ -329,14 +434,14 @@ void Curl_ntlm_core_mk_lm_hash(struct SessionHandle *data, * The LanManager hashed password needs to be created using the * password in the network encoding not the host encoding. */ - res = Curl_convert_to_network(data, (char *)pw, 14); - if(res) - return; + result = Curl_convert_to_network(data, (char *)pw, 14); + if(result) + return result; { /* Create LanManager hashed password. */ -#ifdef USE_SSLEAY +#ifdef USE_OPENSSL DES_key_schedule ks; setup_des_key(pw, DESKEY(ks)); @@ -364,13 +469,16 @@ void Curl_ntlm_core_mk_lm_hash(struct SessionHandle *data, setup_des_key(pw + 7, &des); gcry_cipher_encrypt(des, lmbuffer + 8, 8, magic, 8); gcry_cipher_close(des); -#elif defined(USE_NSS) || defined(USE_DARWINSSL) +#elif defined(USE_NSS) || defined(USE_DARWINSSL) || defined(USE_OS400CRYPTO) \ + || defined(USE_WIN32_CRYPTO) encrypt_des(magic, lmbuffer, pw); encrypt_des(magic, lmbuffer + 8, pw + 7); #endif memset(lmbuffer + 16, 0, 21 - 16); } + + return CURLE_OK; } #if USE_NTRESPONSES @@ -384,6 +492,8 @@ static void ascii_to_unicode_le(unsigned char *dest, const char *src, } } +#if USE_NTLM_V2 && !defined(USE_WINDOWS_SSPI) + static void ascii_uppercase_to_unicode_le(unsigned char *dest, const char *src, size_t srclen) { @@ -394,26 +504,11 @@ static void ascii_uppercase_to_unicode_le(unsigned char *dest, } } -static void write32_le(const int value, unsigned char *buffer) -{ - buffer[0] = (char)(value & 0x000000FF); - buffer[1] = (char)((value & 0x0000FF00) >> 8); - buffer[2] = (char)((value & 0x00FF0000) >> 16); - buffer[3] = (char)((value & 0xFF000000) >> 24); -} - -#if defined(HAVE_LONGLONG) -static void write64_le(const long long value, unsigned char *buffer) -#else -static void write64_le(const __int64 value, unsigned char *buffer) -#endif -{ - write32_le((int)value, buffer); - write32_le((int)(value >> 32), buffer + 4); -} +#endif /* USE_NTLM_V2 && !USE_WINDOWS_SSPI */ /* * Set up nt hashed passwords + * @unittest: 1600 */ CURLcode Curl_ntlm_core_mk_nt_hash(struct SessionHandle *data, const char *password, @@ -437,7 +532,7 @@ CURLcode Curl_ntlm_core_mk_nt_hash(struct SessionHandle *data, { /* Create NT hashed password. */ -#ifdef USE_SSLEAY +#ifdef USE_OPENSSL MD4_CTX MD4pw; MD4_Init(&MD4pw); MD4_Update(&MD4pw, pw, 2 * len); @@ -453,10 +548,23 @@ CURLcode Curl_ntlm_core_mk_nt_hash(struct SessionHandle *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) +#elif defined(USE_NSS) || defined(USE_OS400CRYPTO) Curl_md4it(ntbuffer, pw, 2 * len); #elif defined(USE_DARWINSSL) (void)CC_MD4(pw, (CC_LONG)(2 * len), ntbuffer); +#elif defined(USE_WIN32_CRYPTO) + HCRYPTPROV hprov; + if(CryptAcquireContext(&hprov, NULL, NULL, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT)) { + HCRYPTHASH hhash; + if(CryptCreateHash(hprov, CALG_MD4, 0, 0, &hhash)) { + DWORD length = 16; + CryptHashData(hhash, pw, (unsigned int)len * 2, 0); + CryptGetHashParam(hhash, HP_HASHVAL, ntbuffer, &length, 0); + CryptDestroyHash(hhash); + } + CryptReleaseContext(hprov, 0); + } #endif memset(ntbuffer + 16, 0, 21 - 16); @@ -467,6 +575,8 @@ CURLcode Curl_ntlm_core_mk_nt_hash(struct SessionHandle *data, return CURLE_OK; } +#if USE_NTLM_V2 && !defined(USE_WINDOWS_SSPI) + /* This returns the HMAC MD5 digest */ CURLcode Curl_hmac_md5(const unsigned char *key, unsigned int keylen, const unsigned char *data, unsigned int datalen, @@ -497,7 +607,7 @@ CURLcode Curl_ntlm_core_mk_ntlmv2_hash(const char *user, size_t userlen, /* Unicode representation */ size_t identity_len = (userlen + domlen) * 2; unsigned char *identity = malloc(identity_len); - CURLcode res = CURLE_OK; + CURLcode result = CURLE_OK; if(!identity) return CURLE_OUT_OF_MEMORY; @@ -505,12 +615,12 @@ CURLcode Curl_ntlm_core_mk_ntlmv2_hash(const char *user, size_t userlen, ascii_uppercase_to_unicode_le(identity, user, userlen); ascii_to_unicode_le(identity + (userlen << 1), domain, domlen); - res = Curl_hmac_md5(ntlmhash, 16, identity, curlx_uztoui(identity_len), - ntlmv2hash); + result = Curl_hmac_md5(ntlmhash, 16, identity, curlx_uztoui(identity_len), + ntlmv2hash); - Curl_safefree(identity); + free(identity); - return res; + return result; } /* @@ -559,7 +669,7 @@ CURLcode Curl_ntlm_core_mk_ntlmv2_resp(unsigned char *ntlmv2hash, #else __int64 tw; #endif - CURLcode res = CURLE_OK; + CURLcode result = CURLE_OK; /* Calculate the timestamp */ #ifdef DEBUGBUILD @@ -586,17 +696,17 @@ CURLcode Curl_ntlm_core_mk_ntlmv2_resp(unsigned char *ntlmv2hash, "%c%c%c%c", /* Reserved = 0 */ 0, 0, 0, 0); - write64_le(tw, ptr + 24); + Curl_write64_le(tw, ptr + 24); memcpy(ptr + 32, challenge_client, 8); memcpy(ptr + 44, ntlm->target_info, ntlm->target_info_len); /* Concatenate the Type 2 challenge with the BLOB and do HMAC MD5 */ memcpy(ptr + 8, &ntlm->nonce[0], 8); - res = Curl_hmac_md5(ntlmv2hash, NTLM_HMAC_MD5_LEN, ptr + 8, - NTLMv2_BLOB_LEN + 8, hmac_output); - if(res) { - Curl_safefree(ptr); - return res; + result = Curl_hmac_md5(ntlmv2hash, NTLM_HMAC_MD5_LEN, ptr + 8, + NTLMv2_BLOB_LEN + 8, hmac_output); + if(result) { + free(ptr); + return result; } /* Concatenate the HMAC MD5 output with the BLOB */ @@ -606,7 +716,7 @@ CURLcode Curl_ntlm_core_mk_ntlmv2_resp(unsigned char *ntlmv2hash, *ntresp = ptr; *ntresp_len = len; - return res; + return result; } /* @@ -630,22 +740,26 @@ CURLcode Curl_ntlm_core_mk_lmv2_resp(unsigned char *ntlmv2hash, { unsigned char data[16]; unsigned char hmac_output[16]; - CURLcode res = CURLE_OK; + CURLcode result = CURLE_OK; memcpy(&data[0], challenge_server, 8); memcpy(&data[8], challenge_client, 8); - res = Curl_hmac_md5(ntlmv2hash, 16, &data[0], 16, hmac_output); - if(res) - return res; + result = Curl_hmac_md5(ntlmv2hash, 16, &data[0], 16, hmac_output); + if(result) + return result; /* Concatenate the HMAC MD5 output with the client nonce */ memcpy(lmresp, hmac_output, 16); memcpy(lmresp+16, challenge_client, 8); - return res; + return result; } +#endif /* USE_NTLM_V2 && !USE_WINDOWS_SSPI */ + #endif /* USE_NTRESPONSES */ -#endif /* USE_NTLM && !USE_WINDOWS_SSPI */ +#endif /* !USE_WINDOWS_SSPI || USE_WIN32_CRYPTO */ + +#endif /* USE_NTLM */ diff --git a/Utilities/cmcurl/lib/curl_ntlm_core.h b/Utilities/cmcurl/lib/curl_ntlm_core.h index fe41cdd..3a76359 100644 --- a/Utilities/cmcurl/lib/curl_ntlm_core.h +++ b/Utilities/cmcurl/lib/curl_ntlm_core.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -24,9 +24,11 @@ #include "curl_setup.h" -#if defined(USE_NTLM) && !defined(USE_WINDOWS_SSPI) +#if defined(USE_NTLM) -#ifdef USE_SSLEAY +#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." @@ -34,38 +36,49 @@ # ifdef OPENSSL_NO_MD4 # define USE_NTRESPONSES 0 # define USE_NTLM2SESSION 0 +# define USE_NTLM_V2 0 # endif #endif -/* - * Define USE_NTRESPONSES to 1 in order to make the type-3 message include - * the NT response message. Define USE_NTLM2SESSION to 1 in order to make - * the type-3 message include the NTLM2Session response message, requires - * USE_NTRESPONSES defined to 1. - */ - +/* Define USE_NTRESPONSES to 1 in order to make the type-3 message include + * the NT response message. */ #ifndef USE_NTRESPONSES -# define USE_NTRESPONSES 1 -# define USE_NTLM2SESSION 1 +#define USE_NTRESPONSES 1 +#endif + +/* Define USE_NTLM2SESSION to 1 in order to make the type-3 message include the + NTLM2Session response message, requires USE_NTRESPONSES defined to 1 and a + Crypto engine that we have curl_ssl_md5sum() for. */ +#if !defined(USE_NTLM2SESSION) && USE_NTRESPONSES && !defined(USE_WIN32_CRYPTO) +#define USE_NTLM2SESSION 1 +#endif + +/* Define USE_NTLM_V2 to 1 in order to allow the type-3 message to include the + LMv2 and NTLMv2 response messages, requires USE_NTRESPONSES defined to 1 + and support for 64-bit integers. */ +#if !defined(USE_NTLM_V2) && USE_NTRESPONSES && (CURL_SIZEOF_CURL_OFF_T > 4) +#define USE_NTLM_V2 1 #endif void Curl_ntlm_core_lm_resp(const unsigned char *keys, const unsigned char *plaintext, unsigned char *results); -void Curl_ntlm_core_mk_lm_hash(struct SessionHandle *data, - const char *password, - unsigned char *lmbuffer /* 21 bytes */); +CURLcode Curl_ntlm_core_mk_lm_hash(struct SessionHandle *data, + const char *password, + unsigned char *lmbuffer /* 21 bytes */); #if USE_NTRESPONSES -CURLcode Curl_hmac_md5(const unsigned char *key, unsigned int keylen, - const unsigned char *data, unsigned int datalen, - unsigned char *output); - CURLcode Curl_ntlm_core_mk_nt_hash(struct SessionHandle *data, const char *password, unsigned char *ntbuffer /* 21 bytes */); +#if USE_NTLM_V2 && !defined(USE_WINDOWS_SSPI) + +CURLcode Curl_hmac_md5(const unsigned char *key, unsigned int keylen, + const unsigned char *data, unsigned int datalen, + unsigned char *output); + CURLcode Curl_ntlm_core_mk_ntlmv2_hash(const char *user, size_t userlen, const char *domain, size_t domlen, unsigned char *ntlmhash, @@ -82,8 +95,12 @@ CURLcode Curl_ntlm_core_mk_lmv2_resp(unsigned char *ntlmv2hash, unsigned char *challenge_server, unsigned char *lmresp); -#endif +#endif /* USE_NTLM_V2 && !USE_WINDOWS_SSPI */ + +#endif /* USE_NTRESPONSES */ + +#endif /* !USE_WINDOWS_SSPI || USE_WIN32_CRYPTO */ -#endif /* USE_NTLM && !USE_WINDOWS_SSPI */ +#endif /* USE_NTLM */ #endif /* HEADER_CURL_NTLM_CORE_H */ diff --git a/Utilities/cmcurl/lib/curl_ntlm_msgs.c b/Utilities/cmcurl/lib/curl_ntlm_msgs.c index b807926..7f07dec 100644 --- a/Utilities/cmcurl/lib/curl_ntlm_msgs.c +++ b/Utilities/cmcurl/lib/curl_ntlm_msgs.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -22,7 +22,7 @@ #include "curl_setup.h" -#ifdef USE_NTLM +#if defined(USE_NTLM) && !defined(USE_WINDOWS_SSPI) /* * NTLM details: @@ -41,21 +41,21 @@ #include "curl_gethostname.h" #include "curl_multibyte.h" #include "warnless.h" -#include "curl_memory.h" - -#ifdef USE_WINDOWS_SSPI -# include "curl_sspi.h" -#endif #include "vtls/vtls.h" +#ifdef USE_NSS +#include "vtls/nssg.h" /* for Curl_nss_force_init() */ +#endif + #define BUILDING_CURL_NTLM_MSGS_C #include "curl_ntlm_msgs.h" +#include "curl_sasl.h" +#include "curl_endian.h" +#include "curl_printf.h" -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - -/* The last #include file should be: */ +/* The last #include files should be: */ +#include "curl_memory.h" #include "memdebug.h" /* "NTLMSSP" signature is always in ASCII regardless of the platform */ @@ -147,63 +147,38 @@ static void ntlm_print_hex(FILE *handle, const char *buf, size_t len) # define DEBUG_OUT(x) Curl_nop_stmt #endif -#ifndef USE_WINDOWS_SSPI -/* - * This function converts from the little endian format used in the - * incoming package to whatever endian format we're using natively. - * Argument is a pointer to a 4 byte buffer. - */ -static unsigned int readint_le(unsigned char *buf) -{ - return ((unsigned int)buf[0]) | ((unsigned int)buf[1] << 8) | - ((unsigned int)buf[2] << 16) | ((unsigned int)buf[3] << 24); -} - -/* - * This function converts from the little endian format used in the incoming - * package to whatever endian format we're using natively. Argument is a - * pointer to a 2 byte buffer. - */ -static unsigned int readshort_le(unsigned char *buf) -{ - return ((unsigned int)buf[0]) | ((unsigned int)buf[1] << 8); -} - /* - * Curl_ntlm_decode_type2_target() + * ntlm_decode_type2_target() * * This is used to decode the "target info" in the ntlm type-2 message * received. * * Parameters: * - * data [in] - Pointer to the session handle - * buffer [in] - The decoded base64 ntlm header of Type 2 - * size [in] - The input buffer size, atleast 32 bytes - * ntlm [in] - Pointer to ntlm data struct being used and modified. + * data [in] - The session handle. + * buffer [in] - The decoded type-2 message. + * size [in] - The input buffer size, at least 32 bytes. + * ntlm [in/out] - The ntlm data struct being used and modified. * * Returns CURLE_OK on success. */ -CURLcode Curl_ntlm_decode_type2_target(struct SessionHandle *data, - unsigned char *buffer, - size_t size, - struct ntlmdata *ntlm) +static CURLcode ntlm_decode_type2_target(struct SessionHandle *data, + unsigned char *buffer, + size_t size, + struct ntlmdata *ntlm) { - unsigned int target_info_len = 0; + unsigned short target_info_len = 0; unsigned int target_info_offset = 0; - Curl_safefree(ntlm->target_info); - ntlm->target_info_len = 0; - if(size >= 48) { - target_info_len = readshort_le(&buffer[40]); - target_info_offset = readint_le(&buffer[44]); + target_info_len = Curl_read16_le(&buffer[40]); + target_info_offset = Curl_read32_le(&buffer[44]); if(target_info_len > 0) { if(((target_info_offset + target_info_len) > size) || (target_info_offset < 48)) { infof(data, "NTLM handshake failure (bad type-2 message). " "Target Info Offset Len is set incorrect by the peer\n"); - return CURLE_REMOTE_ACCESS_DENIED; + return CURLE_BAD_CONTENT_ENCODING; } ntlm->target_info = malloc(target_info_len); @@ -211,17 +186,14 @@ CURLcode Curl_ntlm_decode_type2_target(struct SessionHandle *data, return CURLE_OUT_OF_MEMORY; memcpy(ntlm->target_info, &buffer[target_info_offset], target_info_len); - ntlm->target_info_len = target_info_len; - } - } + ntlm->target_info_len = target_info_len; + return CURLE_OK; } -#endif - /* NTLM message structure notes: @@ -239,29 +211,26 @@ CURLcode Curl_ntlm_decode_type2_target(struct SessionHandle *data, */ /* - * Curl_ntlm_decode_type2_message() + * Curl_sasl_decode_ntlm_type2_message() * - * This is used to decode a ntlm type-2 message received from a HTTP or SASL - * based (such as SMTP, POP3 or IMAP) server. The message is first decoded - * from a base64 string into a raw ntlm message and checked for validity - * before the appropriate data for creating a type-3 message is written to - * the given ntlm data structure. + * This is used to decode an already encoded NTLM type-2 message. The message + * is first decoded from a base64 string into a raw NTLM message and checked + * for validity before the appropriate data for creating a type-3 message is + * written to the given NTLM data structure. * * Parameters: * - * data [in] - Pointer to session handle. - * header [in] - Pointer to the input buffer. - * ntlm [in] - Pointer to ntlm data struct being used and modified. + * data [in] - The session handle. + * type2msg [in] - The base64 encoded type-2 message. + * ntlm [in/out] - The ntlm data struct being used and modified. * * Returns CURLE_OK on success. */ -CURLcode Curl_ntlm_decode_type2_message(struct SessionHandle *data, - const char *header, - struct ntlmdata *ntlm) +CURLcode Curl_sasl_decode_ntlm_type2_message(struct SessionHandle *data, + const char *type2msg, + struct ntlmdata *ntlm) { -#ifndef USE_WINDOWS_SSPI static const char type2_marker[] = { 0x02, 0x00, 0x00, 0x00 }; -#endif /* NTLM type-2 message structure: @@ -279,52 +248,52 @@ CURLcode Curl_ntlm_decode_type2_message(struct SessionHandle *data, (*) -> Optional */ - size_t size = 0; - unsigned char *buffer = NULL; - CURLcode error; - -#if defined(CURL_DISABLE_VERBOSE_STRINGS) || defined(USE_WINDOWS_SSPI) + CURLcode result = CURLE_OK; + unsigned char *type2 = NULL; + size_t type2_len = 0; + +#if defined(USE_NSS) + /* Make sure the crypto backend is initialized */ + result = Curl_nss_force_init(data); + if(result) + return result; +#elif defined(CURL_DISABLE_VERBOSE_STRINGS) (void)data; #endif - error = Curl_base64_decode(header, &buffer, &size); - if(error) - return error; - - if(!buffer) { - infof(data, "NTLM handshake failure (unhandled condition)\n"); - return CURLE_REMOTE_ACCESS_DENIED; + /* Decode the base-64 encoded type-2 message */ + if(strlen(type2msg) && *type2msg != '=') { + result = Curl_base64_decode(type2msg, &type2, &type2_len); + if(result) + return result; } -#ifdef USE_WINDOWS_SSPI - ntlm->type_2 = malloc(size + 1); - if(ntlm->type_2 == NULL) { - free(buffer); - return CURLE_OUT_OF_MEMORY; + /* Ensure we have a valid type-2 message */ + if(!type2) { + infof(data, "NTLM handshake failure (empty type-2 message)\n"); + return CURLE_BAD_CONTENT_ENCODING; } - ntlm->n_type_2 = curlx_uztoul(size); - memcpy(ntlm->type_2, buffer, size); -#else + ntlm->flags = 0; - if((size < 32) || - (memcmp(buffer, NTLMSSP_SIGNATURE, 8) != 0) || - (memcmp(buffer + 8, type2_marker, sizeof(type2_marker)) != 0)) { + if((type2_len < 32) || + (memcmp(type2, NTLMSSP_SIGNATURE, 8) != 0) || + (memcmp(type2 + 8, type2_marker, sizeof(type2_marker)) != 0)) { /* This was not a good enough type-2 message */ - free(buffer); + free(type2); infof(data, "NTLM handshake failure (bad type-2 message)\n"); - return CURLE_REMOTE_ACCESS_DENIED; + return CURLE_BAD_CONTENT_ENCODING; } - ntlm->flags = readint_le(&buffer[20]); - memcpy(ntlm->nonce, &buffer[24], 8); + ntlm->flags = Curl_read32_le(&type2[20]); + memcpy(ntlm->nonce, &type2[24], 8); if(ntlm->flags & NTLMFLAG_NEGOTIATE_TARGET_INFO) { - error = Curl_ntlm_decode_type2_target(data, buffer, size, ntlm); - if(error) { - free(buffer); + result = ntlm_decode_type2_target(data, type2, type2_len, ntlm); + if(result) { + free(type2); infof(data, "NTLM handshake failure (bad type-2 message)\n"); - return error; + return result; } } @@ -336,32 +305,12 @@ CURLcode Curl_ntlm_decode_type2_message(struct SessionHandle *data, fprintf(stderr, "\n****\n"); fprintf(stderr, "**** Header %s\n ", header); }); -#endif - free(buffer); - - return CURLE_OK; -} -#ifdef USE_WINDOWS_SSPI -void Curl_ntlm_sspi_cleanup(struct ntlmdata *ntlm) -{ - Curl_safefree(ntlm->type_2); + free(type2); - if(ntlm->has_handles) { - s_pSecFn->DeleteSecurityContext(&ntlm->c_handle); - s_pSecFn->FreeCredentialsHandle(&ntlm->handle); - ntlm->has_handles = 0; - } - - ntlm->max_token_length = 0; - Curl_safefree(ntlm->output_token); - - Curl_sspi_free_identity(ntlm->p_identity); - ntlm->p_identity = NULL; + return result; } -#endif -#ifndef USE_WINDOWS_SSPI /* copy the source to the destination and fill in zeroes in every other destination byte! */ static void unicodecpy(unsigned char *dest, const char *src, size_t length) @@ -372,14 +321,12 @@ static void unicodecpy(unsigned char *dest, const char *src, size_t length) dest[2 * i + 1] = '\0'; } } -#endif /* - * Curl_ntlm_create_type1_message() + * Curl_sasl_create_ntlm_type1_message() * * This is used to generate an already encoded NTLM type-1 message ready for - * sending to the recipient, be it a HTTP or SASL based (such as SMTP, POP3 - * or IMAP) server, using the appropriate compile time crypo API. + * sending to the recipient using the appropriate compile time crypto API. * * Parameters: * @@ -392,11 +339,10 @@ static void unicodecpy(unsigned char *dest, const char *src, size_t length) * * Returns CURLE_OK on success. */ -CURLcode Curl_ntlm_create_type1_message(const char *userp, - const char *passwdp, - struct ntlmdata *ntlm, - char **outptr, - size_t *outlen) +CURLcode Curl_sasl_create_ntlm_type1_message(const char *userp, + const char *passwdp, + struct ntlmdata *ntlm, + char **outptr, size_t *outlen) { /* NTLM type-1 message structure: @@ -414,89 +360,6 @@ CURLcode Curl_ntlm_create_type1_message(const char *userp, size_t size; -#ifdef USE_WINDOWS_SSPI - - PSecPkgInfo SecurityPackage; - SecBuffer type_1_buf; - SecBufferDesc type_1_desc; - SECURITY_STATUS status; - unsigned long attrs; - TimeStamp tsDummy; /* For Windows 9x compatibility of SSPI calls */ - - Curl_ntlm_sspi_cleanup(ntlm); - - /* Query the security package for NTLM */ - status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT("NTLM"), - &SecurityPackage); - if(status != SEC_E_OK) - return CURLE_NOT_BUILT_IN; - - ntlm->max_token_length = SecurityPackage->cbMaxToken; - - /* Release the package buffer as it is not required anymore */ - s_pSecFn->FreeContextBuffer(SecurityPackage); - - /* Allocate our output buffer */ - ntlm->output_token = malloc(ntlm->max_token_length); - if(!ntlm->output_token) - return CURLE_OUT_OF_MEMORY; - - if(userp && *userp) { - CURLcode result; - - /* Populate our identity structure */ - result = Curl_create_sspi_identity(userp, passwdp, &ntlm->identity); - if(result) - return result; - - /* Allow proper cleanup of the identity structure */ - ntlm->p_identity = &ntlm->identity; - } - else - /* Use the current Windows user */ - ntlm->p_identity = NULL; - - /* Acquire our credientials handle */ - status = s_pSecFn->AcquireCredentialsHandle(NULL, - (TCHAR *) TEXT("NTLM"), - SECPKG_CRED_OUTBOUND, NULL, - ntlm->p_identity, NULL, NULL, - &ntlm->handle, &tsDummy); - if(status != SEC_E_OK) - return CURLE_OUT_OF_MEMORY; - - /* Setup the type-1 "output" security buffer */ - type_1_desc.ulVersion = SECBUFFER_VERSION; - type_1_desc.cBuffers = 1; - type_1_desc.pBuffers = &type_1_buf; - type_1_buf.BufferType = SECBUFFER_TOKEN; - type_1_buf.pvBuffer = ntlm->output_token; - type_1_buf.cbBuffer = curlx_uztoul(ntlm->max_token_length); - - /* Generate our type-1 message */ - status = s_pSecFn->InitializeSecurityContext(&ntlm->handle, NULL, - (TCHAR *) TEXT(""), - ISC_REQ_CONFIDENTIALITY | - ISC_REQ_REPLAY_DETECT | - ISC_REQ_CONNECTION, - 0, SECURITY_NETWORK_DREP, - NULL, 0, - &ntlm->c_handle, &type_1_desc, - &attrs, &tsDummy); - - if(status == SEC_I_COMPLETE_AND_CONTINUE || - status == SEC_I_CONTINUE_NEEDED) - s_pSecFn->CompleteAuthToken(&ntlm->c_handle, &type_1_desc); - else if(status != SEC_E_OK) { - s_pSecFn->FreeCredentialsHandle(&ntlm->handle); - return CURLE_RECV_ERROR; - } - - ntlm->has_handles = 1; - size = type_1_buf.cbBuffer; - -#else - unsigned char ntlmbuf[NTLM_BUFSIZE]; const char *host = ""; /* empty */ const char *domain = ""; /* empty */ @@ -507,9 +370,11 @@ CURLcode Curl_ntlm_create_type1_message(const char *userp, domain are empty */ (void)userp; (void)passwdp; - (void)ntlm; -#if USE_NTLM2SESSION + /* Clean up any former leftovers and initialise to defaults */ + Curl_sasl_ntlm_cleanup(ntlm); + +#if USE_NTRESPONSES && USE_NTLM2SESSION #define NTLM2FLAG NTLMFLAG_NEGOTIATE_NTLM2_KEY #else #define NTLM2FLAG 0 @@ -550,8 +415,6 @@ CURLcode Curl_ntlm_create_type1_message(const char *userp, /* Initial packet length */ size = 32 + hostlen + domlen; -#endif - DEBUG_OUT({ fprintf(stderr, "* TYPE1 header flags=0x%02.2x%02.2x%02.2x%02.2x " "0x%08.8x ", @@ -575,20 +438,14 @@ CURLcode Curl_ntlm_create_type1_message(const char *userp, }); /* Return with binary blob encoded into base64 */ -#ifdef USE_WINDOWS_SSPI - return Curl_base64_encode(NULL, (char *)ntlm->output_token, size, - outptr, outlen); -#else return Curl_base64_encode(NULL, (char *)ntlmbuf, size, outptr, outlen); -#endif } /* - * Curl_ntlm_create_type3_message() + * Curl_sasl_create_ntlm_type3_message() * * This is used to generate an already encoded NTLM type-3 message ready for - * sending to the recipient, be it a HTTP or SASL based (such as SMTP, POP3 - * or IMAP) server, using the appropriate compile time crypo API. + * sending to the recipient using the appropriate compile time crypto API. * * Parameters: * @@ -602,12 +459,12 @@ CURLcode Curl_ntlm_create_type1_message(const char *userp, * * Returns CURLE_OK on success. */ -CURLcode Curl_ntlm_create_type3_message(struct SessionHandle *data, - const char *userp, - const char *passwdp, - struct ntlmdata *ntlm, - char **outptr, - size_t *outlen) +CURLcode Curl_sasl_create_ntlm_type3_message(struct SessionHandle *data, + const char *userp, + const char *passwdp, + struct ntlmdata *ntlm, + char **outptr, size_t *outlen) + { /* NTLM type-3 message structure: @@ -627,65 +484,8 @@ CURLcode Curl_ntlm_create_type3_message(struct SessionHandle *data, (*) -> Optional */ - size_t size; - -#ifdef USE_WINDOWS_SSPI CURLcode result = CURLE_OK; - SecBuffer type_2_buf; - SecBuffer type_3_buf; - SecBufferDesc type_2_desc; - SecBufferDesc type_3_desc; - SECURITY_STATUS status; - unsigned long attrs; - TimeStamp tsDummy; /* For Windows 9x compatibility of SSPI calls */ - - (void)passwdp; - (void)userp; - (void)data; - - /* Setup the type-2 "input" security buffer */ - type_2_desc.ulVersion = SECBUFFER_VERSION; - type_2_desc.cBuffers = 1; - type_2_desc.pBuffers = &type_2_buf; - type_2_buf.BufferType = SECBUFFER_TOKEN; - type_2_buf.pvBuffer = ntlm->type_2; - type_2_buf.cbBuffer = ntlm->n_type_2; - - /* Setup the type-3 "output" security buffer */ - type_3_desc.ulVersion = SECBUFFER_VERSION; - type_3_desc.cBuffers = 1; - type_3_desc.pBuffers = &type_3_buf; - type_3_buf.BufferType = SECBUFFER_TOKEN; - type_3_buf.pvBuffer = ntlm->output_token; - type_3_buf.cbBuffer = curlx_uztoul(ntlm->max_token_length); - - /* Generate our type-3 message */ - status = s_pSecFn->InitializeSecurityContext(&ntlm->handle, - &ntlm->c_handle, - (TCHAR *) TEXT(""), - ISC_REQ_CONFIDENTIALITY | - ISC_REQ_REPLAY_DETECT | - ISC_REQ_CONNECTION, - 0, SECURITY_NETWORK_DREP, - &type_2_desc, - 0, &ntlm->c_handle, - &type_3_desc, - &attrs, &tsDummy); - if(status != SEC_E_OK) - return CURLE_RECV_ERROR; - - size = type_3_buf.cbBuffer; - - /* Return with binary blob encoded into base64 */ - result = Curl_base64_encode(NULL, (char *)ntlm->output_token, size, - outptr, outlen); - - Curl_ntlm_sspi_cleanup(ntlm); - - return result; - -#else - + size_t size; unsigned char ntlmbuf[NTLM_BUFSIZE]; int lmrespoff; unsigned char lmresp[24]; /* fixed-size */ @@ -706,7 +506,6 @@ CURLcode Curl_ntlm_create_type3_message(struct SessionHandle *data, size_t hostlen = 0; size_t userlen = 0; size_t domlen = 0; - CURLcode res = CURLE_OK; user = strchr(userp, '\\'); if(!user) @@ -733,7 +532,7 @@ CURLcode Curl_ntlm_create_type3_message(struct SessionHandle *data, hostlen = strlen(host); } -#if USE_NTRESPONSES +#if USE_NTRESPONSES && USE_NTLM_V2 if(ntlm->target_info_len) { unsigned char ntbuffer[0x18]; unsigned int entropy[2]; @@ -742,35 +541,35 @@ CURLcode Curl_ntlm_create_type3_message(struct SessionHandle *data, entropy[0] = Curl_rand(data); entropy[1] = Curl_rand(data); - res = Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer); - if(res) - return res; + result = Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer); + if(result) + return result; - res = Curl_ntlm_core_mk_ntlmv2_hash(user, userlen, domain, domlen, - ntbuffer, ntlmv2hash); - if(res) - return res; + result = Curl_ntlm_core_mk_ntlmv2_hash(user, userlen, domain, domlen, + ntbuffer, ntlmv2hash); + if(result) + return result; /* LMv2 response */ - res = Curl_ntlm_core_mk_lmv2_resp(ntlmv2hash, - (unsigned char *)&entropy[0], - &ntlm->nonce[0], lmresp); - if(res) - return res; + result = Curl_ntlm_core_mk_lmv2_resp(ntlmv2hash, + (unsigned char *)&entropy[0], + &ntlm->nonce[0], lmresp); + if(result) + return result; /* NTLMv2 response */ - res = Curl_ntlm_core_mk_ntlmv2_resp(ntlmv2hash, - (unsigned char *)&entropy[0], - ntlm, &ntlmv2resp, &ntresplen); - if(res) - return res; + result = Curl_ntlm_core_mk_ntlmv2_resp(ntlmv2hash, + (unsigned char *)&entropy[0], + ntlm, &ntlmv2resp, &ntresplen); + if(result) + return result; ptr_ntresp = ntlmv2resp; } else #endif -#if USE_NTLM2SESSION +#if USE_NTRESPONSES && USE_NTLM2SESSION /* We don't support NTLM2 if we don't have USE_NTRESPONSES */ if(ntlm->flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) { unsigned char ntbuffer[0x18]; @@ -792,13 +591,13 @@ CURLcode Curl_ntlm_create_type3_message(struct SessionHandle *data, memcpy(tmp, &ntlm->nonce[0], 8); memcpy(tmp + 8, entropy, 8); - Curl_ssl_md5sum(tmp, 16, md5sum, MD5_DIGEST_LENGTH); - - /* We shall only use the first 8 bytes of md5sum, but the des - code in Curl_ntlm_core_lm_resp only encrypt the first 8 bytes */ - if(CURLE_OUT_OF_MEMORY == - Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer)) - return CURLE_OUT_OF_MEMORY; + result = Curl_ssl_md5sum(tmp, 16, md5sum, MD5_DIGEST_LENGTH); + if(!result) + /* We shall only use the first 8 bytes of md5sum, but the des code in + Curl_ntlm_core_lm_resp only encrypt the first 8 bytes */ + result = Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer); + if(result) + return result; Curl_ntlm_core_lm_resp(ntbuffer, md5sum, ntresp); @@ -815,14 +614,19 @@ CURLcode Curl_ntlm_create_type3_message(struct SessionHandle *data, unsigned char lmbuffer[0x18]; #if USE_NTRESPONSES - if(CURLE_OUT_OF_MEMORY == - Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer)) - return CURLE_OUT_OF_MEMORY; + result = Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer); + if(result) + return result; + Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], ntresp); #endif - Curl_ntlm_core_mk_lm_hash(data, passwdp, lmbuffer); + result = Curl_ntlm_core_mk_lm_hash(data, passwdp, lmbuffer); + if(result) + return result; + Curl_ntlm_core_lm_resp(lmbuffer, &ntlm->nonce[0], lmresp); + /* A safer but less compatible alternative is: * Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], lmresp); * See http://davenport.sourceforge.net/ntlm.html#ntlmVersion2 */ @@ -954,7 +758,7 @@ CURLcode Curl_ntlm_create_type3_message(struct SessionHandle *data, ntlm_print_hex(stderr, (char *)&ntlmbuf[ntrespoff], ntresplen); }); - Curl_safefree(ntlmv2resp);/* Free the dynamic buffer allocated for NTLMv2 */ + free(ntlmv2resp);/* Free the dynamic buffer allocated for NTLMv2 */ #endif @@ -997,14 +801,17 @@ CURLcode Curl_ntlm_create_type3_message(struct SessionHandle *data, size += hostlen; /* Convert domain, user, and host to ASCII but leave the rest as-is */ - res = Curl_convert_to_network(data, (char *)&ntlmbuf[domoff], - size - domoff); - if(res) + result = Curl_convert_to_network(data, (char *)&ntlmbuf[domoff], + size - domoff); + if(result) return CURLE_CONV_FAILED; /* Return with binary blob encoded into base64 */ - return Curl_base64_encode(NULL, (char *)ntlmbuf, size, outptr, outlen); -#endif + result = Curl_base64_encode(NULL, (char *)ntlmbuf, size, outptr, outlen); + + Curl_sasl_ntlm_cleanup(ntlm); + + return result; } -#endif /* USE_NTLM */ +#endif /* USE_NTLM && !USE_WINDOWS_SSPI */ diff --git a/Utilities/cmcurl/lib/curl_ntlm_msgs.h b/Utilities/cmcurl/lib/curl_ntlm_msgs.h index 80413c8..2a71431 100644 --- a/Utilities/cmcurl/lib/curl_ntlm_msgs.h +++ b/Utilities/cmcurl/lib/curl_ntlm_msgs.h @@ -26,40 +26,6 @@ #ifdef USE_NTLM -/* This is to generate a base64 encoded NTLM type-1 message */ -CURLcode Curl_ntlm_create_type1_message(const char *userp, - const char *passwdp, - struct ntlmdata *ntlm, - char **outptr, - size_t *outlen); - -/* This is to generate a base64 encoded NTLM type-3 message */ -CURLcode Curl_ntlm_create_type3_message(struct SessionHandle *data, - const char *userp, - const char *passwdp, - struct ntlmdata *ntlm, - char **outptr, - size_t *outlen); - -/* This is to decode a NTLM type-2 message */ -CURLcode Curl_ntlm_decode_type2_message(struct SessionHandle *data, - const char* header, - struct ntlmdata* ntlm); - -/* This is to decode target info received in NTLM type-2 message */ -CURLcode Curl_ntlm_decode_type2_target(struct SessionHandle *data, - unsigned char* buffer, - size_t size, - struct ntlmdata* ntlm); - - -/* This is to clean up the ntlm data structure */ -#ifdef USE_WINDOWS_SSPI -void Curl_ntlm_sspi_cleanup(struct ntlmdata *ntlm); -#else -#define Curl_ntlm_sspi_cleanup(x) -#endif - /* NTLM buffer fixed size, large enough for long user + host + domain */ #define NTLM_BUFSIZE 1024 diff --git a/Utilities/cmcurl/lib/curl_ntlm_wb.c b/Utilities/cmcurl/lib/curl_ntlm_wb.c index 23ee726..b2a5fb3 100644 --- a/Utilities/cmcurl/lib/curl_ntlm_wb.c +++ b/Utilities/cmcurl/lib/curl_ntlm_wb.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -22,7 +22,8 @@ #include "curl_setup.h" -#if defined(USE_NTLM) && defined(NTLM_WB_ENABLED) +#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \ + defined(NTLM_WB_ENABLED) /* * NTLM details: @@ -50,12 +51,10 @@ #include "curl_ntlm_wb.h" #include "url.h" #include "strerror.h" -#include "curl_memory.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> +#include "curl_printf.h" -/* The last #include file should be: */ +/* The last #include files should be: */ +#include "curl_memory.h" #include "memdebug.h" #if DEBUG_ME @@ -106,9 +105,9 @@ void Curl_ntlm_wb_cleanup(struct connectdata *conn) conn->ntlm_auth_hlpr_pid = 0; } - Curl_safefree(conn->challenge_header); + free(conn->challenge_header); conn->challenge_header = NULL; - Curl_safefree(conn->response_header); + free(conn->response_header); conn->response_header = NULL; } @@ -245,13 +244,13 @@ static CURLcode ntlm_wb_init(struct connectdata *conn, const char *userp) sclose(sockfds[1]); conn->ntlm_auth_hlpr_socket = sockfds[0]; conn->ntlm_auth_hlpr_pid = child_pid; - Curl_safefree(domain); - Curl_safefree(ntlm_auth_alloc); + free(domain); + free(ntlm_auth_alloc); return CURLE_OK; done: - Curl_safefree(domain); - Curl_safefree(ntlm_auth_alloc); + free(domain); + free(ntlm_auth_alloc); return CURLE_REMOTE_ACCESS_DENIED; } @@ -293,7 +292,7 @@ static CURLcode ntlm_wb_response(struct connectdata *conn, len_out += size; if(buf[len_out - 1] == '\n') { buf[len_out - 1] = '\0'; - goto wrfinish; + break; } newbuf = realloc(buf, len_out + NTLM_BUFSIZE); if(!newbuf) { @@ -302,13 +301,12 @@ static CURLcode ntlm_wb_response(struct connectdata *conn, } buf = newbuf; } - goto done; -wrfinish: + /* Samba/winbind installed but not configured */ if(state == NTLMSTATE_TYPE1 && len_out == 3 && buf[0] == 'P' && buf[1] == 'W') - return CURLE_REMOTE_ACCESS_DENIED; + goto done; /* invalid response */ if(len_out < 4) goto done; @@ -391,12 +389,12 @@ CURLcode Curl_output_ntlm_wb(struct connectdata *conn, if(res) return res; - Curl_safefree(*allocuserpwd); + free(*allocuserpwd); *allocuserpwd = aprintf("%sAuthorization: %s\r\n", proxy ? "Proxy-" : "", conn->response_header); DEBUG_OUT(fprintf(stderr, "**** Header %s\n ", *allocuserpwd)); - Curl_safefree(conn->response_header); + free(conn->response_header); conn->response_header = NULL; break; case NTLMSTATE_TYPE2: @@ -409,7 +407,7 @@ CURLcode Curl_output_ntlm_wb(struct connectdata *conn, if(res) return res; - Curl_safefree(*allocuserpwd); + free(*allocuserpwd); *allocuserpwd = aprintf("%sAuthorization: %s\r\n", proxy ? "Proxy-" : "", conn->response_header); @@ -421,10 +419,8 @@ CURLcode Curl_output_ntlm_wb(struct connectdata *conn, case NTLMSTATE_TYPE3: /* connection is already authenticated, * don't send a header in future requests */ - if(*allocuserpwd) { - free(*allocuserpwd); - *allocuserpwd=NULL; - } + free(*allocuserpwd); + *allocuserpwd=NULL; authp->done = TRUE; break; } @@ -432,4 +428,4 @@ CURLcode Curl_output_ntlm_wb(struct connectdata *conn, return CURLE_OK; } -#endif /* USE_NTLM && NTLM_WB_ENABLED */ +#endif /* !CURL_DISABLE_HTTP && USE_NTLM && NTLM_WB_ENABLED */ diff --git a/Utilities/cmcurl/lib/curl_ntlm_wb.h b/Utilities/cmcurl/lib/curl_ntlm_wb.h index db6bc16..828bb57 100644 --- a/Utilities/cmcurl/lib/curl_ntlm_wb.h +++ b/Utilities/cmcurl/lib/curl_ntlm_wb.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -24,7 +24,8 @@ #include "curl_setup.h" -#if defined(USE_NTLM) && defined(NTLM_WB_ENABLED) +#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \ + defined(NTLM_WB_ENABLED) /* this is for creating ntlm header output by delegating challenge/response to Samba's winbind daemon helper ntlm_auth */ @@ -32,6 +33,6 @@ CURLcode Curl_output_ntlm_wb(struct connectdata *conn, bool proxy); void Curl_ntlm_wb_cleanup(struct connectdata *conn); -#endif /* USE_NTLM && NTLM_WB_ENABLED */ +#endif /* !CURL_DISABLE_HTTP && USE_NTLM && NTLM_WB_ENABLED */ #endif /* HEADER_CURL_NTLM_WB_H */ diff --git a/Utilities/cmcurl/lib/curl_printf.h b/Utilities/cmcurl/lib/curl_printf.h new file mode 100644 index 0000000..086923f --- /dev/null +++ b/Utilities/cmcurl/lib/curl_printf.h @@ -0,0 +1,56 @@ +#ifndef HEADER_CURL_PRINTF_H +#define HEADER_CURL_PRINTF_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ + +/* + * This header should be included by ALL code in libcurl that uses any + * *rintf() functions. + */ + +#include <curl/mprintf.h> + +# undef printf +# undef fprintf +# undef snprintf +# undef vprintf +# undef vfprintf +# undef vsnprintf +# undef aprintf +# undef vaprintf +# define printf curl_mprintf +# define fprintf curl_mfprintf +# define snprintf curl_msnprintf +# define vprintf curl_mvprintf +# define vfprintf curl_mvfprintf +# define vsnprintf curl_mvsnprintf +# define aprintf curl_maprintf +# define vaprintf curl_mvaprintf + +/* We define away the sprintf functions unconditonally since we don't want + internal code to be using them, intentionally or by mistake!*/ +# undef sprintf +# undef vsprintf +# define sprintf sprintf_was_used +# define vsprintf vsprintf_was_used + +#endif /* HEADER_CURL_PRINTF_H */ diff --git a/Utilities/cmcurl/lib/curl_rtmp.c b/Utilities/cmcurl/lib/curl_rtmp.c index e0c24b0..2938972 100644 --- a/Utilities/cmcurl/lib/curl_rtmp.c +++ b/Utilities/cmcurl/lib/curl_rtmp.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2012 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2012 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * Copyright (C) 2010, Howard Chu, <hyc@highlandsun.com> * * This software is licensed as described in the file COPYING, which @@ -32,10 +32,6 @@ #include "warnless.h" #include <curl/curl.h> #include <librtmp/rtmp.h> - -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" @@ -49,7 +45,7 @@ #define DEF_BUFTIME (2*60*60*1000) /* 2 hours */ -static CURLcode rtmp_setup(struct connectdata *conn); +static CURLcode rtmp_setup_connection(struct connectdata *conn); static CURLcode rtmp_do(struct connectdata *conn, bool *done); static CURLcode rtmp_done(struct connectdata *conn, CURLcode, bool premature); static CURLcode rtmp_connect(struct connectdata *conn, bool *done); @@ -64,7 +60,7 @@ static Curl_send rtmp_send; const struct Curl_handler Curl_handler_rtmp = { "RTMP", /* scheme */ - rtmp_setup, /* setup_connection */ + rtmp_setup_connection, /* setup_connection */ rtmp_do, /* do_it */ rtmp_done, /* done */ ZERO_NULL, /* do_more */ @@ -84,7 +80,7 @@ const struct Curl_handler Curl_handler_rtmp = { const struct Curl_handler Curl_handler_rtmpt = { "RTMPT", /* scheme */ - rtmp_setup, /* setup_connection */ + rtmp_setup_connection, /* setup_connection */ rtmp_do, /* do_it */ rtmp_done, /* done */ ZERO_NULL, /* do_more */ @@ -104,7 +100,7 @@ const struct Curl_handler Curl_handler_rtmpt = { const struct Curl_handler Curl_handler_rtmpe = { "RTMPE", /* scheme */ - rtmp_setup, /* setup_connection */ + rtmp_setup_connection, /* setup_connection */ rtmp_do, /* do_it */ rtmp_done, /* done */ ZERO_NULL, /* do_more */ @@ -124,7 +120,7 @@ const struct Curl_handler Curl_handler_rtmpe = { const struct Curl_handler Curl_handler_rtmpte = { "RTMPTE", /* scheme */ - rtmp_setup, /* setup_connection */ + rtmp_setup_connection, /* setup_connection */ rtmp_do, /* do_it */ rtmp_done, /* done */ ZERO_NULL, /* do_more */ @@ -144,7 +140,7 @@ const struct Curl_handler Curl_handler_rtmpte = { const struct Curl_handler Curl_handler_rtmps = { "RTMPS", /* scheme */ - rtmp_setup, /* setup_connection */ + rtmp_setup_connection, /* setup_connection */ rtmp_do, /* do_it */ rtmp_done, /* done */ ZERO_NULL, /* do_more */ @@ -164,7 +160,7 @@ const struct Curl_handler Curl_handler_rtmps = { const struct Curl_handler Curl_handler_rtmpts = { "RTMPTS", /* scheme */ - rtmp_setup, /* setup_connection */ + rtmp_setup_connection, /* setup_connection */ rtmp_do, /* do_it */ rtmp_done, /* done */ ZERO_NULL, /* do_more */ @@ -182,10 +178,9 @@ const struct Curl_handler Curl_handler_rtmpts = { PROTOPT_NONE /* flags*/ }; -static CURLcode rtmp_setup(struct connectdata *conn) +static CURLcode rtmp_setup_connection(struct connectdata *conn) { RTMP *r = RTMP_Alloc(); - if(!r) return CURLE_OUT_OF_MEMORY; @@ -202,7 +197,7 @@ static CURLcode rtmp_setup(struct connectdata *conn) static CURLcode rtmp_connect(struct connectdata *conn, bool *done) { RTMP *r = conn->proto.generic; - SET_RCVTIMEO(tv,10); + SET_RCVTIMEO(tv, 10); r->m_sb.sb_socket = conn->sock[FIRSTSOCKET]; @@ -217,7 +212,7 @@ static CURLcode rtmp_connect(struct connectdata *conn, bool *done) !(r->Link.protocol & RTMP_FEATURE_HTTP)) r->Link.lFlags |= RTMP_LF_BUFX; - curlx_nonblock(r->m_sb.sb_socket, FALSE); + (void)curlx_nonblock(r->m_sb.sb_socket, FALSE); setsockopt(r->m_sb.sb_socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)); diff --git a/Utilities/cmcurl/lib/curl_sasl.c b/Utilities/cmcurl/lib/curl_sasl.c index 7e2b8af..68646bc 100644 --- a/Utilities/cmcurl/lib/curl_sasl.c +++ b/Utilities/cmcurl/lib/curl_sasl.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2012 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2012 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -19,6 +19,7 @@ * KIND, either express or implied. * * RFC2195 CRAM-MD5 authentication + * RFC2617 Basic and Digest Access Authentication * RFC2831 DIGEST-MD5 authentication * RFC4422 Simple Authentication and Security Layer (SASL) * RFC4616 PLAIN authentication @@ -36,26 +37,35 @@ #include "curl_md5.h" #include "vtls/vtls.h" #include "curl_hmac.h" -#include "curl_ntlm_msgs.h" #include "curl_sasl.h" #include "warnless.h" -#include "curl_memory.h" #include "strtok.h" +#include "strequal.h" #include "rawstr.h" +#include "sendf.h" +#include "non-ascii.h" /* included for Curl_convert_... prototypes */ +#include "curl_printf.h" -#ifdef USE_NSS -#include "vtls/nssg.h" /* for Curl_nss_force_init() */ -#endif - -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - -/* The last #include file should be: */ +/* The last #include files should be: */ +#include "curl_memory.h" #include "memdebug.h" -#if defined(USE_WINDOWS_SSPI) -extern void Curl_sasl_gssapi_cleanup(struct kerberos5data *krb5); -#endif +/* Supported mechanisms */ +const struct { + const char *name; /* Name */ + size_t len; /* Name length */ + unsigned int bit; /* Flag bit */ +} mechtable[] = { + { "LOGIN", 5, SASL_MECH_LOGIN }, + { "PLAIN", 5, SASL_MECH_PLAIN }, + { "CRAM-MD5", 8, SASL_MECH_CRAM_MD5 }, + { "DIGEST-MD5", 10, SASL_MECH_DIGEST_MD5 }, + { "GSSAPI", 6, SASL_MECH_GSSAPI }, + { "EXTERNAL", 8, SASL_MECH_EXTERNAL }, + { "NTLM", 4, SASL_MECH_NTLM }, + { "XOAUTH2", 7, SASL_MECH_XOAUTH2 }, + { ZERO_NULL, 0, 0 } +}; #if !defined(CURL_DISABLE_CRYPTO_AUTH) && !defined(USE_WINDOWS_SSPI) #define DIGEST_QOP_VALUE_AUTH (1 << 0) @@ -66,6 +76,131 @@ extern void Curl_sasl_gssapi_cleanup(struct kerberos5data *krb5); #define DIGEST_QOP_VALUE_STRING_AUTH_INT "auth-int" #define DIGEST_QOP_VALUE_STRING_AUTH_CONF "auth-conf" +/* The CURL_OUTPUT_DIGEST_CONV macro below is for non-ASCII machines. + It converts digest text to ASCII so the MD5 will be correct for + what ultimately goes over the network. +*/ +#define CURL_OUTPUT_DIGEST_CONV(a, b) \ + result = Curl_convert_to_network(a, (char *)b, strlen((const char*)b)); \ + if(result) { \ + free(b); \ + return result; \ + } + +#endif + +#if !defined(CURL_DISABLE_CRYPTO_AUTH) +/* + * Returns 0 on success and then the buffers are filled in fine. + * + * Non-zero means failure to parse. + */ +int Curl_sasl_digest_get_pair(const char *str, char *value, char *content, + const char **endptr) +{ + int c; + bool starts_with_quote = FALSE; + bool escape = FALSE; + + for(c = DIGEST_MAX_VALUE_LENGTH - 1; (*str && (*str != '=') && c--); ) + *value++ = *str++; + *value = 0; + + if('=' != *str++) + /* eek, no match */ + return 1; + + if('\"' == *str) { + /* this starts with a quote so it must end with one as well! */ + str++; + starts_with_quote = TRUE; + } + + for(c = DIGEST_MAX_CONTENT_LENGTH - 1; *str && c--; str++) { + switch(*str) { + case '\\': + if(!escape) { + /* possibly the start of an escaped quote */ + escape = TRUE; + *content++ = '\\'; /* even though this is an escape character, we still + store it as-is in the target buffer */ + continue; + } + break; + case ',': + if(!starts_with_quote) { + /* this signals the end of the content if we didn't get a starting + quote and then we do "sloppy" parsing */ + c = 0; /* the end */ + continue; + } + break; + case '\r': + case '\n': + /* end of string */ + c = 0; + continue; + case '\"': + if(!escape && starts_with_quote) { + /* end of string */ + c = 0; + continue; + } + break; + } + escape = FALSE; + *content++ = *str; + } + *content = 0; + + *endptr = str; + + return 0; /* all is fine! */ +} +#endif + +#if !defined(CURL_DISABLE_CRYPTO_AUTH) && !defined(USE_WINDOWS_SSPI) +/* Convert md5 chunk to RFC2617 (section 3.1.3) -suitable ascii string*/ +static void sasl_digest_md5_to_ascii(unsigned char *source, /* 16 bytes */ + unsigned char *dest) /* 33 bytes */ +{ + int i; + for(i = 0; i < 16; i++) + snprintf((char *)&dest[i*2], 3, "%02x", source[i]); +} + +/* Perform quoted-string escaping as described in RFC2616 and its errata */ +static char *sasl_digest_string_quoted(const char *source) +{ + char *dest, *d; + const char *s = source; + size_t n = 1; /* null terminator */ + + /* Calculate size needed */ + while(*s) { + ++n; + if(*s == '"' || *s == '\\') { + ++n; + } + ++s; + } + + dest = malloc(n); + if(dest) { + s = source; + d = dest; + while(*s) { + if(*s == '"' || *s == '\\') { + *d++ = '\\'; + } + *d++ = *s++; + } + *d = 0; + } + + return dest; +} + /* Retrieves the value for a corresponding key from the challenge string * returns TRUE if the key could be found, FALSE if it does not exists */ @@ -118,11 +253,11 @@ static CURLcode sasl_digest_get_qop_values(const char *options, int *value) token = strtok_r(NULL, ",", &tok_buf); } - Curl_safefree(tmp); + free(tmp); return CURLE_OK; } -#endif +#endif /* !CURL_DISABLE_CRYPTO_AUTH && !USE_WINDOWS_SSPI */ #if !defined(USE_WINDOWS_SSPI) /* @@ -132,8 +267,8 @@ static CURLcode sasl_digest_get_qop_values(const char *options, int *value) * * Parameters: * - * serivce [in] - The service type such as www, smtp, pop or imap. - * instance [in] - The instance name such as the host nme or realm. + * service [in] - The service type such as www, smtp, pop or imap. + * host [in] - The host name or realm. * * Returns a pointer to the newly allocated SPN. */ @@ -145,7 +280,7 @@ char *Curl_sasl_build_spn(const char *service, const char *host) #endif /* - * Curl_sasl_create_plain_message() + * sasl_create_plain_message() * * This is used to generate an already encoded PLAIN message ready * for sending to the recipient. @@ -161,10 +296,10 @@ char *Curl_sasl_build_spn(const char *service, const char *host) * * Returns CURLE_OK on success. */ -CURLcode Curl_sasl_create_plain_message(struct SessionHandle *data, - const char *userp, - const char *passwdp, - char **outptr, size_t *outlen) +static CURLcode sasl_create_plain_message(struct SessionHandle *data, + const char *userp, + const char *passwdp, + char **outptr, size_t *outlen) { CURLcode result; char *plainauth; @@ -191,12 +326,12 @@ CURLcode Curl_sasl_create_plain_message(struct SessionHandle *data, /* Base64 encode the reply */ result = Curl_base64_encode(data, plainauth, 2 * ulen + plen + 2, outptr, outlen); - Curl_safefree(plainauth); + free(plainauth); return result; } /* - * Curl_sasl_create_login_message() + * sasl_create_login_message() * * This is used to generate an already encoded LOGIN message containing the * user name or password ready for sending to the recipient. @@ -211,9 +346,9 @@ CURLcode Curl_sasl_create_plain_message(struct SessionHandle *data, * * Returns CURLE_OK on success. */ -CURLcode Curl_sasl_create_login_message(struct SessionHandle *data, - const char *valuep, char **outptr, - size_t *outlen) +static CURLcode sasl_create_login_message(struct SessionHandle *data, + const char *valuep, char **outptr, + size_t *outlen) { size_t vlen = strlen(valuep); @@ -233,23 +368,47 @@ CURLcode Curl_sasl_create_login_message(struct SessionHandle *data, return Curl_base64_encode(data, valuep, vlen, outptr, outlen); } +/* + * sasl_create_external_message() + * + * This is used to generate an already encoded EXTERNAL message containing + * the user name ready for sending to the recipient. + * + * Parameters: + * + * data [in] - The session handle. + * user [in] - The user name. + * outptr [in/out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +static CURLcode sasl_create_external_message(struct SessionHandle *data, + const char *user, char **outptr, + size_t *outlen) +{ + /* This is the same formatting as the login message. */ + return sasl_create_login_message(data, user, outptr, outlen); +} + #ifndef CURL_DISABLE_CRYPTO_AUTH /* - * Curl_sasl_decode_cram_md5_message() + * sasl_decode_cram_md5_message() * * This is used to decode an already encoded CRAM-MD5 challenge message. * * Parameters: * - * chlg64 [in] - Pointer to the base64 encoded challenge message. + * chlg64 [in] - The base64 encoded challenge message. * outptr [in/out] - The address where a pointer to newly allocated memory * holding the result will be stored upon completion. * outlen [out] - The length of the output message. * * Returns CURLE_OK on success. */ -CURLcode Curl_sasl_decode_cram_md5_message(const char *chlg64, char **outptr, - size_t *outlen) +static CURLcode sasl_decode_cram_md5_message(const char *chlg64, char **outptr, + size_t *outlen) { CURLcode result = CURLE_OK; size_t chlg64len = strlen(chlg64); @@ -265,7 +424,7 @@ CURLcode Curl_sasl_decode_cram_md5_message(const char *chlg64, char **outptr, } /* - * Curl_sasl_create_cram_md5_message() + * sasl_create_cram_md5_message() * * This is used to generate an already encoded CRAM-MD5 response message ready * for sending to the recipient. @@ -282,11 +441,11 @@ CURLcode Curl_sasl_decode_cram_md5_message(const char *chlg64, char **outptr, * * Returns CURLE_OK on success. */ -CURLcode Curl_sasl_create_cram_md5_message(struct SessionHandle *data, - const char *chlg, - const char *userp, - const char *passwdp, - char **outptr, size_t *outlen) +static CURLcode sasl_create_cram_md5_message(struct SessionHandle *data, + const char *chlg, + const char *userp, + const char *passwdp, + char **outptr, size_t *outlen) { CURLcode result = CURLE_OK; size_t chlglen = 0; @@ -324,7 +483,7 @@ CURLcode Curl_sasl_create_cram_md5_message(struct SessionHandle *data, /* Base64 encode the response */ result = Curl_base64_encode(data, response, 0, outptr, outlen); - Curl_safefree(response); + free(response); return result; } @@ -338,7 +497,7 @@ CURLcode Curl_sasl_create_cram_md5_message(struct SessionHandle *data, * * Parameters: * - * chlg64 [in] - Pointer to the base64 encoded challenge message. + * chlg64 [in] - The base64 encoded challenge message. * nonce [in/out] - The buffer where the nonce will be stored. * nlen [in] - The length of the nonce buffer. * realm [in/out] - The buffer where the realm will be stored. @@ -374,7 +533,7 @@ static CURLcode sasl_decode_digest_md5_message(const char *chlg64, /* Retrieve nonce string from the challenge */ if(!sasl_digest_get_key_value((char *)chlg, "nonce=\"", nonce, nlen, '\"')) { - Curl_safefree(chlg); + free(chlg); return CURLE_BAD_CONTENT_ENCODING; } @@ -386,17 +545,17 @@ static CURLcode sasl_decode_digest_md5_message(const char *chlg64, /* Retrieve algorithm string from the challenge */ if(!sasl_digest_get_key_value((char *)chlg, "algorithm=", alg, alen, ',')) { - Curl_safefree(chlg); + free(chlg); return CURLE_BAD_CONTENT_ENCODING; } /* Retrieve qop-options string from the challenge */ if(!sasl_digest_get_key_value((char *)chlg, "qop=\"", qop, qlen, '\"')) { - Curl_safefree(chlg); + free(chlg); return CURLE_BAD_CONTENT_ENCODING; } - Curl_safefree(chlg); + free(chlg); return CURLE_OK; } @@ -410,7 +569,7 @@ static CURLcode sasl_decode_digest_md5_message(const char *chlg64, * Parameters: * * data [in] - The session handle. - * chlg64 [in] - Pointer to the base64 encoded challenge message. + * chlg64 [in] - The base64 encoded challenge message. * userp [in] - The user name. * passdwp [in] - The user's password. * service [in] - The service type such as www, smtp, pop or imap. @@ -518,7 +677,7 @@ CURLcode Curl_sasl_create_digest_md5_message(struct SessionHandle *data, /* Calculate H(A2) */ ctxt = Curl_MD5_init(Curl_DIGEST_MD5); if(!ctxt) { - Curl_safefree(spn); + free(spn); return CURLE_OUT_OF_MEMORY; } @@ -536,7 +695,7 @@ CURLcode Curl_sasl_create_digest_md5_message(struct SessionHandle *data, /* Now calculate the response hash */ ctxt = Curl_MD5_init(Curl_DIGEST_MD5); if(!ctxt) { - Curl_safefree(spn); + free(spn); return CURLE_OUT_OF_MEMORY; } @@ -569,110 +728,432 @@ CURLcode Curl_sasl_create_digest_md5_message(struct SessionHandle *data, "qop=%s", userp, realm, nonce, cnonce, nonceCount, spn, resp_hash_hex, qop); - Curl_safefree(spn); + free(spn); if(!response) return CURLE_OUT_OF_MEMORY; /* Base64 encode the response */ result = Curl_base64_encode(data, response, 0, outptr, outlen); - Curl_safefree(response); + free(response); return result; } -#endif /* !USE_WINDOWS_SSPI */ -#endif /* CURL_DISABLE_CRYPTO_AUTH */ - -#ifdef USE_NTLM /* - * Curl_sasl_create_ntlm_type1_message() + * Curl_sasl_decode_digest_http_message() * - * This is used to generate an already encoded NTLM type-1 message ready for - * sending to the recipient. + * This is used to decode a HTTP DIGEST challenge message into the seperate + * attributes. * - * Note: This is a simple wrapper of the NTLM function which means that any - * SASL based protocols don't have to include the NTLM functions directly. + * Parameters: + * + * chlg [in] - The challenge message. + * digest [in/out] - The digest data struct being used and modified. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_sasl_decode_digest_http_message(const char *chlg, + struct digestdata *digest) +{ + bool before = FALSE; /* got a nonce before */ + bool foundAuth = FALSE; + bool foundAuthInt = FALSE; + char *token = NULL; + char *tmp = NULL; + + /* If we already have received a nonce, keep that in mind */ + if(digest->nonce) + before = TRUE; + + /* Clean up any former leftovers and initialise to defaults */ + Curl_sasl_digest_cleanup(digest); + + for(;;) { + char value[DIGEST_MAX_VALUE_LENGTH]; + char content[DIGEST_MAX_CONTENT_LENGTH]; + + /* Pass all additional spaces here */ + while(*chlg && ISSPACE(*chlg)) + chlg++; + + /* Extract a value=content pair */ + if(!Curl_sasl_digest_get_pair(chlg, value, content, &chlg)) { + if(Curl_raw_equal(value, "nonce")) { + digest->nonce = strdup(content); + if(!digest->nonce) + return CURLE_OUT_OF_MEMORY; + } + else if(Curl_raw_equal(value, "stale")) { + if(Curl_raw_equal(content, "true")) { + digest->stale = TRUE; + digest->nc = 1; /* we make a new nonce now */ + } + } + else if(Curl_raw_equal(value, "realm")) { + digest->realm = strdup(content); + if(!digest->realm) + return CURLE_OUT_OF_MEMORY; + } + else if(Curl_raw_equal(value, "opaque")) { + digest->opaque = strdup(content); + if(!digest->opaque) + return CURLE_OUT_OF_MEMORY; + } + else if(Curl_raw_equal(value, "qop")) { + char *tok_buf; + /* Tokenize the list and choose auth if possible, use a temporary + clone of the buffer since strtok_r() ruins it */ + tmp = strdup(content); + if(!tmp) + return CURLE_OUT_OF_MEMORY; + + token = strtok_r(tmp, ",", &tok_buf); + while(token != NULL) { + if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH)) { + foundAuth = TRUE; + } + else if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH_INT)) { + foundAuthInt = TRUE; + } + token = strtok_r(NULL, ",", &tok_buf); + } + + free(tmp); + + /* Select only auth or auth-int. Otherwise, ignore */ + if(foundAuth) { + digest->qop = strdup(DIGEST_QOP_VALUE_STRING_AUTH); + if(!digest->qop) + return CURLE_OUT_OF_MEMORY; + } + else if(foundAuthInt) { + digest->qop = strdup(DIGEST_QOP_VALUE_STRING_AUTH_INT); + if(!digest->qop) + return CURLE_OUT_OF_MEMORY; + } + } + else if(Curl_raw_equal(value, "algorithm")) { + digest->algorithm = strdup(content); + if(!digest->algorithm) + return CURLE_OUT_OF_MEMORY; + + if(Curl_raw_equal(content, "MD5-sess")) + digest->algo = CURLDIGESTALGO_MD5SESS; + else if(Curl_raw_equal(content, "MD5")) + digest->algo = CURLDIGESTALGO_MD5; + else + return CURLE_BAD_CONTENT_ENCODING; + } + else { + /* unknown specifier, ignore it! */ + } + } + else + break; /* we're done here */ + + /* Pass all additional spaces here */ + while(*chlg && ISSPACE(*chlg)) + chlg++; + + /* Allow the list to be comma-separated */ + if(',' == *chlg) + chlg++; + } + + /* We had a nonce since before, and we got another one now without + 'stale=true'. This means we provided bad credentials in the previous + request */ + if(before && !digest->stale) + return CURLE_BAD_CONTENT_ENCODING; + + /* We got this header without a nonce, that's a bad Digest line! */ + if(!digest->nonce) + return CURLE_BAD_CONTENT_ENCODING; + + return CURLE_OK; +} + +/* + * Curl_sasl_create_digest_http_message() + * + * This is used to generate a HTTP DIGEST response message ready for sending + * to the recipient. * * Parameters: * - * userp [in] - The user name in the format User or Domain\User. + * data [in] - The session handle. + * userp [in] - The user name. * passdwp [in] - The user's password. - * ntlm [in/out] - The ntlm data struct being used and modified. + * request [in] - The HTTP request. + * uripath [in] - The path of the HTTP uri. + * digest [in/out] - The digest data struct being used and modified. * outptr [in/out] - The address where a pointer to newly allocated memory * holding the result will be stored upon completion. * outlen [out] - The length of the output message. * * Returns CURLE_OK on success. */ -CURLcode Curl_sasl_create_ntlm_type1_message(const char *userp, - const char *passwdp, - struct ntlmdata *ntlm, - char **outptr, size_t *outlen) +CURLcode Curl_sasl_create_digest_http_message(struct SessionHandle *data, + const char *userp, + const char *passwdp, + const unsigned char *request, + const unsigned char *uripath, + struct digestdata *digest, + char **outptr, size_t *outlen) { - return Curl_ntlm_create_type1_message(userp, passwdp, ntlm, outptr, outlen); + CURLcode result; + unsigned char md5buf[16]; /* 16 bytes/128 bits */ + unsigned char request_digest[33]; + unsigned char *md5this; + unsigned char ha1[33];/* 32 digits and 1 zero byte */ + unsigned char ha2[33];/* 32 digits and 1 zero byte */ + char cnoncebuf[33]; + char *cnonce = NULL; + size_t cnonce_sz = 0; + char *userp_quoted; + char *response = NULL; + char *tmp = NULL; + + if(!digest->nc) + digest->nc = 1; + + if(!digest->cnonce) { + snprintf(cnoncebuf, sizeof(cnoncebuf), "%08x%08x%08x%08x", + Curl_rand(data), Curl_rand(data), + Curl_rand(data), Curl_rand(data)); + + result = Curl_base64_encode(data, cnoncebuf, strlen(cnoncebuf), + &cnonce, &cnonce_sz); + if(result) + return result; + + digest->cnonce = cnonce; + } + + /* + if the algorithm is "MD5" or unspecified (which then defaults to MD5): + + A1 = unq(username-value) ":" unq(realm-value) ":" passwd + + if the algorithm is "MD5-sess" then: + + A1 = H( unq(username-value) ":" unq(realm-value) ":" passwd ) + ":" unq(nonce-value) ":" unq(cnonce-value) + */ + + md5this = (unsigned char *) + aprintf("%s:%s:%s", userp, digest->realm, passwdp); + if(!md5this) + return CURLE_OUT_OF_MEMORY; + + CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */ + Curl_md5it(md5buf, md5this); + free(md5this); + sasl_digest_md5_to_ascii(md5buf, ha1); + + if(digest->algo == CURLDIGESTALGO_MD5SESS) { + /* nonce and cnonce are OUTSIDE the hash */ + tmp = aprintf("%s:%s:%s", ha1, digest->nonce, digest->cnonce); + if(!tmp) + return CURLE_OUT_OF_MEMORY; + + CURL_OUTPUT_DIGEST_CONV(data, tmp); /* convert on non-ASCII machines */ + Curl_md5it(md5buf, (unsigned char *)tmp); + free(tmp); + sasl_digest_md5_to_ascii(md5buf, ha1); + } + + /* + If the "qop" directive's value is "auth" or is unspecified, then A2 is: + + A2 = Method ":" digest-uri-value + + If the "qop" value is "auth-int", then A2 is: + + A2 = Method ":" digest-uri-value ":" H(entity-body) + + (The "Method" value is the HTTP request method as specified in section + 5.1.1 of RFC 2616) + */ + + md5this = (unsigned char *)aprintf("%s:%s", request, uripath); + + if(digest->qop && Curl_raw_equal(digest->qop, "auth-int")) { + /* We don't support auth-int for PUT or POST at the moment. + TODO: replace md5 of empty string with entity-body for PUT/POST */ + unsigned char *md5this2 = (unsigned char *) + aprintf("%s:%s", md5this, "d41d8cd98f00b204e9800998ecf8427e"); + free(md5this); + md5this = md5this2; + } + + if(!md5this) + return CURLE_OUT_OF_MEMORY; + + CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */ + Curl_md5it(md5buf, md5this); + free(md5this); + sasl_digest_md5_to_ascii(md5buf, ha2); + + if(digest->qop) { + md5this = (unsigned char *)aprintf("%s:%s:%08x:%s:%s:%s", + ha1, + digest->nonce, + digest->nc, + digest->cnonce, + digest->qop, + ha2); + } + else { + md5this = (unsigned char *)aprintf("%s:%s:%s", + ha1, + digest->nonce, + ha2); + } + + if(!md5this) + return CURLE_OUT_OF_MEMORY; + + CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */ + Curl_md5it(md5buf, md5this); + free(md5this); + sasl_digest_md5_to_ascii(md5buf, request_digest); + + /* for test case 64 (snooped from a Mozilla 1.3a request) + + Authorization: Digest username="testuser", realm="testrealm", \ + nonce="1053604145", uri="/64", response="c55f7f30d83d774a3d2dcacf725abaca" + + Digest parameters are all quoted strings. Username which is provided by + the user will need double quotes and backslashes within it escaped. For + the other fields, this shouldn't be an issue. realm, nonce, and opaque + are copied as is from the server, escapes and all. cnonce is generated + with web-safe characters. uri is already percent encoded. nc is 8 hex + characters. algorithm and qop with standard values only contain web-safe + chracters. + */ + userp_quoted = sasl_digest_string_quoted(userp); + if(!userp_quoted) + return CURLE_OUT_OF_MEMORY; + + if(digest->qop) { + response = aprintf("username=\"%s\", " + "realm=\"%s\", " + "nonce=\"%s\", " + "uri=\"%s\", " + "cnonce=\"%s\", " + "nc=%08x, " + "qop=%s, " + "response=\"%s\"", + userp_quoted, + digest->realm, + digest->nonce, + uripath, + digest->cnonce, + digest->nc, + digest->qop, + request_digest); + + if(Curl_raw_equal(digest->qop, "auth")) + digest->nc++; /* The nc (from RFC) has to be a 8 hex digit number 0 + padded which tells to the server how many times you are + using the same nonce in the qop=auth mode */ + } + else { + response = aprintf("username=\"%s\", " + "realm=\"%s\", " + "nonce=\"%s\", " + "uri=\"%s\", " + "response=\"%s\"", + userp_quoted, + digest->realm, + digest->nonce, + uripath, + request_digest); + } + free(userp_quoted); + if(!response) + return CURLE_OUT_OF_MEMORY; + + /* Add the optional fields */ + if(digest->opaque) { + /* Append the opaque */ + tmp = aprintf("%s, opaque=\"%s\"", response, digest->opaque); + free(response); + if(!tmp) + return CURLE_OUT_OF_MEMORY; + + response = tmp; + } + + if(digest->algorithm) { + /* Append the algorithm */ + tmp = aprintf("%s, algorithm=\"%s\"", response, digest->algorithm); + free(response); + if(!tmp) + return CURLE_OUT_OF_MEMORY; + + response = tmp; + } + + /* Return the output */ + *outptr = response; + *outlen = strlen(response); + + return CURLE_OK; } /* - * Curl_sasl_decode_ntlm_type2_message() + * Curl_sasl_digest_cleanup() * - * This is used to decode an already encoded NTLM type-2 message. + * This is used to clean up the digest specific data. * * Parameters: * - * data [in] - Pointer to session handle. - * type2msg [in] - Pointer to the base64 encoded type-2 message. - * ntlm [in/out] - The ntlm data struct being used and modified. + * digest [in/out] - The digest data struct being cleaned up. * - * Returns CURLE_OK on success. */ -CURLcode Curl_sasl_decode_ntlm_type2_message(struct SessionHandle *data, - const char *type2msg, - struct ntlmdata *ntlm) +void Curl_sasl_digest_cleanup(struct digestdata *digest) { -#ifdef USE_NSS - CURLcode result; - - /* make sure the crypto backend is initialized */ - result = Curl_nss_force_init(data); - if(result) - return result; -#endif - - return Curl_ntlm_decode_type2_message(data, type2msg, ntlm); + Curl_safefree(digest->nonce); + Curl_safefree(digest->cnonce); + Curl_safefree(digest->realm); + Curl_safefree(digest->opaque); + Curl_safefree(digest->qop); + Curl_safefree(digest->algorithm); + + digest->nc = 0; + digest->algo = CURLDIGESTALGO_MD5; /* default algorithm */ + digest->stale = FALSE; /* default means normal, not stale */ } +#endif /* !USE_WINDOWS_SSPI */ + +#endif /* CURL_DISABLE_CRYPTO_AUTH */ +#if defined(USE_NTLM) && !defined(USE_WINDOWS_SSPI) /* - * Curl_sasl_create_ntlm_type3_message() + * Curl_sasl_ntlm_cleanup() * - * This is used to generate an already encoded NTLM type-3 message ready for - * sending to the recipient. + * This is used to clean up the ntlm specific data. * * Parameters: * - * data [in] - Pointer to 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. - * outptr [in/out] - The address where a pointer to newly allocated memory - * holding the result will be stored upon completion. - * outlen [out] - The length of the output message. + * ntlm [in/out] - The ntlm data struct being cleaned up. * - * Returns CURLE_OK on success. */ -CURLcode Curl_sasl_create_ntlm_type3_message(struct SessionHandle *data, - const char *userp, - const char *passwdp, - struct ntlmdata *ntlm, - char **outptr, size_t *outlen) +void Curl_sasl_ntlm_cleanup(struct ntlmdata *ntlm) { - return Curl_ntlm_create_type3_message(data, userp, passwdp, ntlm, outptr, - outlen); + /* Free the target info */ + Curl_safefree(ntlm->target_info); + + /* Reset any variables */ + ntlm->target_info_len = 0; } -#endif /* USE_NTLM */ +#endif /* USE_NTLM && !USE_WINDOWS_SSPI*/ /* - * Curl_sasl_create_xoauth2_message() + * sasl_create_xoauth2_message() * * This is used to generate an already encoded OAuth 2.0 message ready for * sending to the recipient. @@ -688,10 +1169,10 @@ CURLcode Curl_sasl_create_ntlm_type3_message(struct SessionHandle *data, * * Returns CURLE_OK on success. */ -CURLcode Curl_sasl_create_xoauth2_message(struct SessionHandle *data, - const char *user, - const char *bearer, - char **outptr, size_t *outlen) +static CURLcode sasl_create_xoauth2_message(struct SessionHandle *data, + const char *user, + const char *bearer, + char **outptr, size_t *outlen) { CURLcode result = CURLE_OK; char *xoauth = NULL; @@ -704,7 +1185,7 @@ CURLcode Curl_sasl_create_xoauth2_message(struct SessionHandle *data, /* Base64 encode the reply */ result = Curl_base64_encode(data, xoauth, strlen(xoauth), outptr, outlen); - Curl_safefree(xoauth); + free(xoauth); return result; } @@ -717,25 +1198,472 @@ CURLcode Curl_sasl_create_xoauth2_message(struct SessionHandle *data, * * Parameters: * - * conn [in] - Pointer to the connection data. + * conn [in] - The connection data. * authused [in] - The authentication mechanism used. */ void Curl_sasl_cleanup(struct connectdata *conn, unsigned int authused) { -#if defined(USE_WINDOWS_SSPI) +#if defined(USE_KERBEROS5) /* Cleanup the gssapi structure */ if(authused == SASL_MECH_GSSAPI) { Curl_sasl_gssapi_cleanup(&conn->krb5); } -#ifdef USE_NTLM +#endif + +#if defined(USE_NTLM) /* Cleanup the ntlm structure */ - else if(authused == SASL_MECH_NTLM) { - Curl_ntlm_sspi_cleanup(&conn->ntlm); + if(authused == SASL_MECH_NTLM) { + Curl_sasl_ntlm_cleanup(&conn->ntlm); } #endif -#else + +#if !defined(USE_KERBEROS5) && !defined(USE_NTLM) /* Reserved for future use */ (void)conn; (void)authused; #endif } + +/* + * Curl_sasl_decode_mech() + * + * Convert a SASL mechanism name into a token. + * + * Parameters: + * + * ptr [in] - The mechanism string. + * maxlen [in] - Maximum mechanism string length. + * len [out] - If not NULL, effective name length. + * + * Returns the SASL mechanism token or 0 if no match. + */ +unsigned int Curl_sasl_decode_mech(const char *ptr, size_t maxlen, size_t *len) +{ + unsigned int i; + char c; + + for(i = 0; mechtable[i].name; i++) { + if(maxlen >= mechtable[i].len && + !memcmp(ptr, mechtable[i].name, mechtable[i].len)) { + if(len) + *len = mechtable[i].len; + + if(maxlen == mechtable[i].len) + return mechtable[i].bit; + + c = ptr[mechtable[i].len]; + if(!ISUPPER(c) && !ISDIGIT(c) && c != '-' && c != '_') + return mechtable[i].bit; + } + } + + return 0; +} + +/* + * Curl_sasl_parse_url_auth_option() + * + * Parse the URL login options. + */ +CURLcode Curl_sasl_parse_url_auth_option(struct SASL *sasl, + const char *value, size_t len) +{ + CURLcode result = CURLE_OK; + unsigned int mechbit; + size_t mechlen; + + if(!len) + return CURLE_URL_MALFORMAT; + + if(sasl->resetprefs) { + sasl->resetprefs = FALSE; + sasl->prefmech = SASL_AUTH_NONE; + } + + if(strnequal(value, "*", len)) + sasl->prefmech = SASL_AUTH_DEFAULT; + else if((mechbit = Curl_sasl_decode_mech(value, len, &mechlen)) && + mechlen == len) + sasl->prefmech |= mechbit; + else + result = CURLE_URL_MALFORMAT; + + return result; +} + +/* + * Curl_sasl_init() + * + * Initializes the SASL structure. + */ +void Curl_sasl_init(struct SASL *sasl, const struct SASLproto *params) +{ + sasl->params = params; /* Set protocol dependent parameters */ + sasl->state = SASL_STOP; /* Not yet running */ + sasl->authmechs = SASL_AUTH_NONE; /* No known authentication mechanism yet */ + sasl->prefmech = SASL_AUTH_DEFAULT; /* Prefer all mechanisms */ + sasl->authused = SASL_AUTH_NONE; /* No the authentication mechanism used */ + sasl->resetprefs = TRUE; /* Reset prefmech upon AUTH parsing. */ + sasl->mutual_auth = FALSE; /* No mutual authentication (GSSAPI only) */ + sasl->force_ir = FALSE; /* Respect external option */ +} + +/* + * state() + * + * This is the ONLY way to change SASL state! + */ +static void state(struct SASL *sasl, struct connectdata *conn, + saslstate newstate) +{ +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) + /* for debug purposes */ + static const char * const names[]={ + "STOP", + "PLAIN", + "LOGIN", + "LOGIN_PASSWD", + "EXTERNAL", + "CRAMMD5", + "DIGESTMD5", + "DIGESTMD5_RESP", + "NTLM", + "NTLM_TYPE2MSG", + "GSSAPI", + "GSSAPI_TOKEN", + "GSSAPI_NO_DATA", + "XOAUTH2", + "CANCEL", + "FINAL", + /* LAST */ + }; + + if(sasl->state != newstate) + infof(conn->data, "SASL %p state change from %s to %s\n", + (void *)sasl, names[sasl->state], names[newstate]); +#else + (void) conn; +#endif + + sasl->state = newstate; +} + +/* + * Curl_sasl_can_authenticate() + * + * Check if we have enough auth data and capabilities to authenticate. + */ +bool Curl_sasl_can_authenticate(struct SASL *sasl, struct connectdata *conn) +{ + /* Have credentials been provided? */ + if(conn->bits.user_passwd) + return TRUE; + + /* EXTERNAL can authenticate without a user name and/or password */ + if(sasl->authmechs & sasl->prefmech & SASL_MECH_EXTERNAL) + return TRUE; + + return FALSE; +} + +/* + * Curl_sasl_start() + * + * Calculate the required login details for SASL authentication. + */ +CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn, + bool force_ir, saslprogress *progress) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + unsigned int enabledmechs; + const char *mech = NULL; + char *resp = NULL; + size_t len = 0; + saslstate state1 = SASL_STOP; + saslstate state2 = SASL_FINAL; + + sasl->force_ir = force_ir; /* Latch for future use */ + sasl->authused = 0; /* No mechanism used yet */ + enabledmechs = sasl->authmechs & sasl->prefmech; + *progress = SASL_IDLE; + + /* Calculate the supported authentication mechanism, by decreasing order of + security, as well as the initial response where appropriate */ + if((enabledmechs & SASL_MECH_EXTERNAL) && !conn->passwd[0]) { + mech = SASL_MECH_STRING_EXTERNAL; + state1 = SASL_EXTERNAL; + sasl->authused = SASL_MECH_EXTERNAL; + + if(force_ir || data->set.sasl_ir) + result = sasl_create_external_message(data, conn->user, &resp, &len); + } + else if(conn->bits.user_passwd) { +#if defined(USE_KERBEROS5) + if(enabledmechs & SASL_MECH_GSSAPI) { + sasl->mutual_auth = FALSE; /* TODO: Calculate mutual authentication */ + mech = SASL_MECH_STRING_GSSAPI; + state1 = SASL_GSSAPI; + state2 = SASL_GSSAPI_TOKEN; + sasl->authused = SASL_MECH_GSSAPI; + + if(force_ir || data->set.sasl_ir) + result = Curl_sasl_create_gssapi_user_message(data, conn->user, + conn->passwd, + sasl->params->service, + sasl->mutual_auth, + NULL, &conn->krb5, + &resp, &len); + } + else +#endif +#ifndef CURL_DISABLE_CRYPTO_AUTH + if(enabledmechs & SASL_MECH_DIGEST_MD5) { + mech = SASL_MECH_STRING_DIGEST_MD5; + state1 = SASL_DIGESTMD5; + sasl->authused = SASL_MECH_DIGEST_MD5; + } + else if(enabledmechs & SASL_MECH_CRAM_MD5) { + mech = SASL_MECH_STRING_CRAM_MD5; + state1 = SASL_CRAMMD5; + sasl->authused = SASL_MECH_CRAM_MD5; + } + else +#endif +#ifdef USE_NTLM + if(enabledmechs & SASL_MECH_NTLM) { + mech = SASL_MECH_STRING_NTLM; + state1 = SASL_NTLM; + state2 = SASL_NTLM_TYPE2MSG; + sasl->authused = SASL_MECH_NTLM; + + if(force_ir || data->set.sasl_ir) + result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd, + &conn->ntlm, &resp, &len); + } + else +#endif + if((enabledmechs & SASL_MECH_XOAUTH2) || conn->xoauth2_bearer) { + mech = SASL_MECH_STRING_XOAUTH2; + state1 = SASL_XOAUTH2; + sasl->authused = SASL_MECH_XOAUTH2; + + if(force_ir || data->set.sasl_ir) + result = sasl_create_xoauth2_message(data, conn->user, + conn->xoauth2_bearer, + &resp, &len); + } + else if(enabledmechs & SASL_MECH_LOGIN) { + mech = SASL_MECH_STRING_LOGIN; + state1 = SASL_LOGIN; + state2 = SASL_LOGIN_PASSWD; + sasl->authused = SASL_MECH_LOGIN; + + if(force_ir || data->set.sasl_ir) + result = sasl_create_login_message(data, conn->user, &resp, &len); + } + else if(enabledmechs & SASL_MECH_PLAIN) { + mech = SASL_MECH_STRING_PLAIN; + state1 = SASL_PLAIN; + sasl->authused = SASL_MECH_PLAIN; + + if(force_ir || data->set.sasl_ir) + result = sasl_create_plain_message(data, conn->user, conn->passwd, + &resp, &len); + } + } + + if(!result) { + if(resp && sasl->params->maxirlen && + strlen(mech) + len > sasl->params->maxirlen) { + free(resp); + resp = NULL; + } + + if(mech) { + result = sasl->params->sendauth(conn, mech, resp); + if(!result) { + *progress = SASL_INPROGRESS; + state(sasl, conn, resp? state2: state1); + } + } + } + + free(resp); + + return result; +} + +/* + * Curl_sasl_continue() + * + * Continue the authentication. + */ +CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn, + int code, saslprogress *progress) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + saslstate newstate = SASL_FINAL; + char *resp = NULL; +#if !defined(CURL_DISABLE_CRYPTO_AUTH) + char *serverdata; + char *chlg = NULL; + size_t chlglen = 0; +#endif + size_t len = 0; + + *progress = SASL_INPROGRESS; + + if(sasl->state == SASL_FINAL) { + if(code != sasl->params->finalcode) + result = CURLE_LOGIN_DENIED; + *progress = SASL_DONE; + state(sasl, conn, SASL_STOP); + return result; + } + + if(sasl->state != SASL_CANCEL && code != sasl->params->contcode) { + *progress = SASL_DONE; + state(sasl, conn, SASL_STOP); + return CURLE_LOGIN_DENIED; + } + + switch(sasl->state) { + case SASL_STOP: + *progress = SASL_DONE; + return result; + case SASL_PLAIN: + result = sasl_create_plain_message(data, conn->user, conn->passwd, &resp, + &len); + break; + case SASL_LOGIN: + result = sasl_create_login_message(data, conn->user, &resp, &len); + newstate = SASL_LOGIN_PASSWD; + break; + case SASL_LOGIN_PASSWD: + result = sasl_create_login_message(data, conn->passwd, &resp, &len); + break; + case SASL_EXTERNAL: + result = sasl_create_external_message(data, conn->user, &resp, &len); + break; + +#ifndef CURL_DISABLE_CRYPTO_AUTH + case SASL_CRAMMD5: + sasl->params->getmessage(data->state.buffer, &serverdata); + result = sasl_decode_cram_md5_message(serverdata, &chlg, &chlglen); + if(!result) + result = sasl_create_cram_md5_message(data, chlg, conn->user, + conn->passwd, &resp, &len); + free(chlg); + break; + case SASL_DIGESTMD5: + sasl->params->getmessage(data->state.buffer, &serverdata); + result = Curl_sasl_create_digest_md5_message(data, serverdata, + conn->user, conn->passwd, + sasl->params->service, + &resp, &len); + newstate = SASL_DIGESTMD5_RESP; + break; + case SASL_DIGESTMD5_RESP: + if(!(resp = strdup(""))) + result = CURLE_OUT_OF_MEMORY; + break; +#endif + +#ifdef USE_NTLM + case SASL_NTLM: + /* Create the type-1 message */ + result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd, + &conn->ntlm, &resp, &len); + newstate = SASL_NTLM_TYPE2MSG; + break; + case SASL_NTLM_TYPE2MSG: + /* Decode the type-2 message */ + sasl->params->getmessage(data->state.buffer, &serverdata); + result = Curl_sasl_decode_ntlm_type2_message(data, serverdata, + &conn->ntlm); + if(!result) + result = Curl_sasl_create_ntlm_type3_message(data, conn->user, + conn->passwd, &conn->ntlm, + &resp, &len); + break; +#endif + +#if defined(USE_KERBEROS5) + case SASL_GSSAPI: + result = Curl_sasl_create_gssapi_user_message(data, conn->user, + conn->passwd, + sasl->params->service, + sasl->mutual_auth, NULL, + &conn->krb5, + &resp, &len); + newstate = SASL_GSSAPI_TOKEN; + break; + case SASL_GSSAPI_TOKEN: + sasl->params->getmessage(data->state.buffer, &serverdata); + if(sasl->mutual_auth) { + /* Decode the user token challenge and create the optional response + message */ + result = Curl_sasl_create_gssapi_user_message(data, NULL, NULL, NULL, + sasl->mutual_auth, + serverdata, &conn->krb5, + &resp, &len); + newstate = SASL_GSSAPI_NO_DATA; + } + else + /* Decode the security challenge and create the response message */ + result = Curl_sasl_create_gssapi_security_message(data, serverdata, + &conn->krb5, + &resp, &len); + break; + case SASL_GSSAPI_NO_DATA: + sasl->params->getmessage(data->state.buffer, &serverdata); + /* Decode the security challenge and create the response message */ + result = Curl_sasl_create_gssapi_security_message(data, serverdata, + &conn->krb5, + &resp, &len); + break; +#endif + + case SASL_XOAUTH2: + /* Create the authorisation message */ + result = sasl_create_xoauth2_message(data, conn->user, + conn->xoauth2_bearer, &resp, &len); + break; + case SASL_CANCEL: + /* Remove the offending mechanism from the supported list */ + sasl->authmechs ^= sasl->authused; + + /* Start an alternative SASL authentication */ + result = Curl_sasl_start(sasl, conn, sasl->force_ir, progress); + newstate = sasl->state; /* Use state from Curl_sasl_start() */ + break; + default: + failf(data, "Unsupported SASL authentication mechanism"); + result = CURLE_UNSUPPORTED_PROTOCOL; /* Should not happen */ + break; + } + + switch(result) { + case CURLE_BAD_CONTENT_ENCODING: + /* Cancel dialog */ + result = sasl->params->sendcont(conn, "*"); + newstate = SASL_CANCEL; + break; + case CURLE_OK: + if(resp) + result = sasl->params->sendcont(conn, resp); + break; + default: + newstate = SASL_STOP; /* Stop on error */ + *progress = SASL_DONE; + break; + } + + free(resp); + + state(sasl, conn, newstate); + + return result; +} diff --git a/Utilities/cmcurl/lib/curl_sasl.h b/Utilities/cmcurl/lib/curl_sasl.h index e56fa1a..117d60e 100644 --- a/Utilities/cmcurl/lib/curl_sasl.h +++ b/Utilities/cmcurl/lib/curl_sasl.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2012 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2012 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -26,16 +26,19 @@ struct SessionHandle; struct connectdata; + +#if !defined(CURL_DISABLE_CRYPTO_AUTH) +struct digestdata; +#endif + +#if defined(USE_NTLM) struct ntlmdata; +#endif -#if defined(USE_WINDOWS_SSPI) +#if defined(USE_KERBEROS5) struct kerberos5data; #endif -/* Authentication mechanism values */ -#define SASL_AUTH_NONE 0 -#define SASL_AUTH_ANY ~0U - /* Authentication mechanism flags */ #define SASL_MECH_LOGIN (1 << 0) #define SASL_MECH_PLAIN (1 << 1) @@ -46,6 +49,12 @@ struct kerberos5data; #define SASL_MECH_NTLM (1 << 6) #define SASL_MECH_XOAUTH2 (1 << 7) +/* Authentication mechanism values */ +#define SASL_AUTH_NONE 0 +#define SASL_AUTH_ANY ~0U +#define SASL_AUTH_DEFAULT (SASL_AUTH_ANY & \ + ~(SASL_MECH_EXTERNAL | SASL_MECH_XOAUTH2)) + /* Authentication mechanism strings */ #define SASL_MECH_STRING_LOGIN "LOGIN" #define SASL_MECH_STRING_PLAIN "PLAIN" @@ -56,6 +65,70 @@ struct kerberos5data; #define SASL_MECH_STRING_NTLM "NTLM" #define SASL_MECH_STRING_XOAUTH2 "XOAUTH2" +#if !defined(CURL_DISABLE_CRYPTO_AUTH) +#define DIGEST_MAX_VALUE_LENGTH 256 +#define DIGEST_MAX_CONTENT_LENGTH 1024 +#endif + +enum { + CURLDIGESTALGO_MD5, + CURLDIGESTALGO_MD5SESS +}; + +/* SASL machine states */ +typedef enum { + SASL_STOP, + SASL_PLAIN, + SASL_LOGIN, + SASL_LOGIN_PASSWD, + SASL_EXTERNAL, + SASL_CRAMMD5, + SASL_DIGESTMD5, + SASL_DIGESTMD5_RESP, + SASL_NTLM, + SASL_NTLM_TYPE2MSG, + SASL_GSSAPI, + SASL_GSSAPI_TOKEN, + SASL_GSSAPI_NO_DATA, + SASL_XOAUTH2, + SASL_CANCEL, + SASL_FINAL +} saslstate; + +/* Progress indicator */ +typedef enum { + SASL_IDLE, + SASL_INPROGRESS, + SASL_DONE +} saslprogress; + +/* Protocol dependent SASL parameters */ +struct SASLproto { + const char *service; /* The service name */ + int contcode; /* Code to receive when continuation is expected */ + int finalcode; /* Code to receive upon authentication success */ + size_t maxirlen; /* Maximum initial response length */ + CURLcode (*sendauth)(struct connectdata *conn, + const char *mech, const char *ir); + /* Send authentication command */ + CURLcode (*sendcont)(struct connectdata *conn, const char *contauth); + /* Send authentication continuation */ + void (*getmessage)(char *buffer, char **outptr); + /* Get SASL response message */ +}; + +/* Per-connection parameters */ +struct SASL { + const struct SASLproto *params; /* Protocol dependent parameters */ + saslstate state; /* Current machine state */ + unsigned int authmechs; /* Accepted authentication mechanisms */ + unsigned int prefmech; /* Preferred authentication mechanism */ + unsigned int authused; /* Auth mechanism used for the connection */ + bool resetprefs; /* For URL auth option parsing. */ + bool mutual_auth; /* Mutual authentication enabled (GSSAPI only) */ + bool force_ir; /* Protocol always supports initial response */ +}; + /* This is used to test whether the line starts with the given mechanism */ #define sasl_mech_equal(line, wordlen, mech) \ (wordlen == (sizeof(mech) - 1) / sizeof(char) && \ @@ -68,29 +141,15 @@ char *Curl_sasl_build_spn(const char *service, const char *instance); TCHAR *Curl_sasl_build_spn(const char *service, const char *instance); #endif -/* This is used to generate a base64 encoded PLAIN authentication message */ -CURLcode Curl_sasl_create_plain_message(struct SessionHandle *data, - const char *userp, - const char *passwdp, - char **outptr, size_t *outlen); +/* This is used to extract the realm from a challenge message */ +int Curl_sasl_digest_get_pair(const char *str, char *value, char *content, + const char **endptr); -/* This is used to generate a base64 encoded LOGIN authentication message - containing either the user name or password details */ -CURLcode Curl_sasl_create_login_message(struct SessionHandle *data, - const char *valuep, char **outptr, - size_t *outlen); +#if defined(HAVE_GSSAPI) +char *Curl_sasl_build_gssapi_spn(const char *service, const char *host); +#endif #ifndef CURL_DISABLE_CRYPTO_AUTH -/* This is used to decode a base64 encoded CRAM-MD5 challange message */ -CURLcode Curl_sasl_decode_cram_md5_message(const char *chlg64, char **outptr, - size_t *outlen); - -/* This is used to generate a base64 encoded CRAM-MD5 response message */ -CURLcode Curl_sasl_create_cram_md5_message(struct SessionHandle *data, - const char *chlg, - const char *user, - const char *passwdp, - char **outptr, size_t *outlen); /* This is used to generate a base64 encoded DIGEST-MD5 response message */ CURLcode Curl_sasl_create_digest_md5_message(struct SessionHandle *data, @@ -99,6 +158,22 @@ CURLcode Curl_sasl_create_digest_md5_message(struct SessionHandle *data, const char *passwdp, const char *service, char **outptr, size_t *outlen); + +/* This is used to decode a HTTP DIGEST challenge message */ +CURLcode Curl_sasl_decode_digest_http_message(const char *chlg, + struct digestdata *digest); + +/* This is used to generate a HTTP DIGEST response message */ +CURLcode Curl_sasl_create_digest_http_message(struct SessionHandle *data, + const char *userp, + const char *passwdp, + const unsigned char *request, + const unsigned char *uri, + struct digestdata *digest, + char **outptr, size_t *outlen); + +/* This is used to clean up the digest specific data */ +void Curl_sasl_digest_cleanup(struct digestdata *digest); #endif #ifdef USE_NTLM @@ -121,9 +196,12 @@ CURLcode Curl_sasl_create_ntlm_type3_message(struct SessionHandle *data, struct ntlmdata *ntlm, char **outptr, size_t *outlen); +/* This is used to clean up the ntlm specific data */ +void Curl_sasl_ntlm_cleanup(struct ntlmdata *ntlm); + #endif /* USE_NTLM */ -#if defined(USE_WINDOWS_SSPI) +#if defined(USE_KERBEROS5) /* This is used to generate a base64 encoded GSSAPI (Kerberos V5) user token message */ CURLcode Curl_sasl_create_gssapi_user_message(struct SessionHandle *data, @@ -142,17 +220,35 @@ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data, struct kerberos5data *krb5, char **outptr, size_t *outlen); -#endif -/* This is used to generate a base64 encoded XOAUTH2 authentication message - containing the user name and bearer token */ -CURLcode Curl_sasl_create_xoauth2_message(struct SessionHandle *data, - const char *user, - const char *bearer, - char **outptr, size_t *outlen); +/* This is used to clean up the gssapi specific data */ +void Curl_sasl_gssapi_cleanup(struct kerberos5data *krb5); +#endif /* USE_KERBEROS5 */ /* This is used to cleanup any libraries or curl modules used by the sasl functions */ void Curl_sasl_cleanup(struct connectdata *conn, unsigned int authused); +/* Convert a mechanism name to a token */ +unsigned int Curl_sasl_decode_mech(const char *ptr, + size_t maxlen, size_t *len); + +/* Parse the URL login options */ +CURLcode Curl_sasl_parse_url_auth_option(struct SASL *sasl, + const char *value, size_t len); + +/* Initializes an SASL structure */ +void Curl_sasl_init(struct SASL *sasl, const struct SASLproto *params); + +/* Check if we have enough auth data and capabilities to authenticate */ +bool Curl_sasl_can_authenticate(struct SASL *sasl, struct connectdata *conn); + +/* Calculate the required login details for SASL authentication */ +CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn, + bool force_ir, saslprogress *progress); + +/* Continue an SASL authentication */ +CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn, + int code, saslprogress *progress); + #endif /* HEADER_CURL_SASL_H */ diff --git a/Utilities/cmcurl/lib/curl_sasl_gssapi.c b/Utilities/cmcurl/lib/curl_sasl_gssapi.c new file mode 100644 index 0000000..3c6f3ce --- /dev/null +++ b/Utilities/cmcurl/lib/curl_sasl_gssapi.c @@ -0,0 +1,392 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2014 - 2015, Steve Holme, <steve_holme@hotmail.com>. + * Copyright (C) 2015, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(HAVE_GSSAPI) && defined(USE_KERBEROS5) + +#include <curl/curl.h> + +#include "curl_sasl.h" +#include "urldata.h" +#include "curl_base64.h" +#include "curl_gssapi.h" +#include "sendf.h" +#include "curl_printf.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +/* +* Curl_sasl_build_gssapi_spn() +* +* This is used to build a SPN string in the format service@host. +* +* Parameters: +* +* serivce [in] - The service type such as www, smtp, pop or imap. +* host [in] - The host name or realm. +* +* Returns a pointer to the newly allocated SPN. +*/ +char *Curl_sasl_build_gssapi_spn(const char *service, const char *host) +{ + /* Generate and return our SPN */ + return aprintf("%s@%s", service, host); +} + +/* + * Curl_sasl_create_gssapi_user_message() + * + * This is used to generate an already encoded GSSAPI (Kerberos V5) user token + * message ready for sending to the recipient. + * + * Parameters: + * + * data [in] - The session handle. + * userp [in] - The user name. + * passdwp [in] - The user's password. + * service [in] - The service type such as www, smtp, pop or imap. + * mutual_auth [in] - Flag specifing whether or not mutual authentication + * is enabled. + * chlg64 [in] - Pointer to the optional base64 encoded challenge + * message. + * krb5 [in/out] - The gssapi data struct being used and modified. + * outptr [in/out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_sasl_create_gssapi_user_message(struct SessionHandle *data, + const char *userp, + const char *passwdp, + const char *service, + const bool mutual_auth, + const char *chlg64, + struct kerberos5data *krb5, + char **outptr, size_t *outlen) +{ + CURLcode result = CURLE_OK; + size_t chlglen = 0; + unsigned char *chlg = NULL; + OM_uint32 gss_status; + OM_uint32 gss_major_status; + OM_uint32 gss_minor_status; + gss_buffer_desc spn_token = GSS_C_EMPTY_BUFFER; + gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; + gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; + + (void) userp; + (void) passwdp; + + if(krb5->context == GSS_C_NO_CONTEXT) { + /* Generate our SPN */ + char *spn = Curl_sasl_build_gssapi_spn(service, + data->easy_conn->host.name); + if(!spn) + return CURLE_OUT_OF_MEMORY; + + /* Populate the SPN structure */ + spn_token.value = spn; + spn_token.length = strlen(spn); + + /* Import the SPN */ + gss_major_status = gss_import_name(&gss_minor_status, &spn_token, + GSS_C_NT_HOSTBASED_SERVICE, &krb5->spn); + if(GSS_ERROR(gss_major_status)) { + Curl_gss_log_error(data, gss_minor_status, "gss_import_name() failed: "); + + free(spn); + + return CURLE_OUT_OF_MEMORY; + } + + free(spn); + } + else { + /* Decode the base-64 encoded challenge message */ + if(strlen(chlg64) && *chlg64 != '=') { + result = Curl_base64_decode(chlg64, &chlg, &chlglen); + if(result) + return result; + } + + /* Ensure we have a valid challenge message */ + if(!chlg) { + infof(data, "GSSAPI handshake failure (empty challenge message)\n"); + + return CURLE_BAD_CONTENT_ENCODING; + } + + /* Setup the challenge "input" security buffer */ + input_token.value = chlg; + input_token.length = chlglen; + } + + gss_major_status = Curl_gss_init_sec_context(data, + &gss_minor_status, + &krb5->context, + krb5->spn, + &Curl_krb5_mech_oid, + GSS_C_NO_CHANNEL_BINDINGS, + &input_token, + &output_token, + mutual_auth, + NULL); + + free(input_token.value); + + if(GSS_ERROR(gss_major_status)) { + if(output_token.value) + gss_release_buffer(&gss_status, &output_token); + + Curl_gss_log_error(data, gss_minor_status, + "gss_init_sec_context() failed: "); + + return CURLE_RECV_ERROR; + } + + if(output_token.value && output_token.length) { + /* Base64 encode the response */ + result = Curl_base64_encode(data, (char *) output_token.value, + output_token.length, outptr, outlen); + + gss_release_buffer(&gss_status, &output_token); + } + + return result; +} + +/* + * Curl_sasl_create_gssapi_security_message() + * + * This is used to generate an already encoded GSSAPI (Kerberos V5) security + * token message ready for sending to the recipient. + * + * Parameters: + * + * data [in] - The session handle. + * chlg64 [in] - Pointer to the optional base64 encoded challenge message. + * krb5 [in/out] - The gssapi data struct being used and modified. + * outptr [in/out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data, + const char *chlg64, + struct kerberos5data *krb5, + char **outptr, + size_t *outlen) +{ + CURLcode result = CURLE_OK; + size_t chlglen = 0; + size_t messagelen = 0; + unsigned char *chlg = NULL; + unsigned char *message = NULL; + OM_uint32 gss_status; + OM_uint32 gss_major_status; + OM_uint32 gss_minor_status; + gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; + gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; + unsigned int indata = 0; + unsigned int outdata = 0; + gss_qop_t qop = GSS_C_QOP_DEFAULT; + unsigned int sec_layer = 0; + unsigned int max_size = 0; + gss_name_t username = GSS_C_NO_NAME; + gss_buffer_desc username_token; + + /* Decode the base-64 encoded input message */ + if(strlen(chlg64) && *chlg64 != '=') { + result = Curl_base64_decode(chlg64, &chlg, &chlglen); + if(result) + return result; + } + + /* Ensure we have a valid challenge message */ + if(!chlg) { + infof(data, "GSSAPI handshake failure (empty security message)\n"); + + return CURLE_BAD_CONTENT_ENCODING; + } + + /* Get the fully qualified username back from the context */ + gss_major_status = gss_inquire_context(&gss_minor_status, krb5->context, + &username, NULL, NULL, NULL, NULL, + NULL, NULL); + if(GSS_ERROR(gss_major_status)) { + Curl_gss_log_error(data, gss_minor_status, + "gss_inquire_context() failed: "); + + free(chlg); + + return CURLE_OUT_OF_MEMORY; + } + + /* Convert the username from internal format to a displayable token */ + gss_major_status = gss_display_name(&gss_minor_status, username, + &username_token, NULL); + if(GSS_ERROR(gss_major_status)) { + Curl_gss_log_error(data, gss_minor_status, "gss_display_name() failed: "); + + free(chlg); + + return CURLE_OUT_OF_MEMORY; + } + + /* Setup the challenge "input" security buffer */ + input_token.value = chlg; + input_token.length = chlglen; + + /* Decrypt the inbound challenge and obtain the qop */ + gss_major_status = gss_unwrap(&gss_minor_status, krb5->context, &input_token, + &output_token, NULL, &qop); + if(GSS_ERROR(gss_major_status)) { + Curl_gss_log_error(data, gss_minor_status, "gss_unwrap() failed: "); + + gss_release_buffer(&gss_status, &username_token); + free(chlg); + + return CURLE_BAD_CONTENT_ENCODING; + } + + /* Not 4 octets long so fail as per RFC4752 Section 3.1 */ + if(output_token.length != 4) { + infof(data, "GSSAPI handshake failure (invalid security data)\n"); + + gss_release_buffer(&gss_status, &username_token); + free(chlg); + + return CURLE_BAD_CONTENT_ENCODING; + } + + /* Copy the data out and free the challenge as it is not required anymore */ + memcpy(&indata, output_token.value, 4); + gss_release_buffer(&gss_status, &output_token); + free(chlg); + + /* Extract the security layer */ + sec_layer = indata & 0x000000FF; + if(!(sec_layer & GSSAUTH_P_NONE)) { + infof(data, "GSSAPI handshake failure (invalid security layer)\n"); + + gss_release_buffer(&gss_status, &username_token); + + return CURLE_BAD_CONTENT_ENCODING; + } + + /* Extract the maximum message size the server can receive */ + max_size = ntohl(indata & 0xFFFFFF00); + if(max_size > 0) { + /* The server has told us it supports a maximum receive buffer, however, as + we don't require one unless we are encrypting data, we tell the server + our receive buffer is zero. */ + max_size = 0; + } + + /* Allocate our message */ + messagelen = sizeof(outdata) + username_token.length + 1; + message = malloc(messagelen); + if(!message) { + gss_release_buffer(&gss_status, &username_token); + + return CURLE_OUT_OF_MEMORY; + } + + /* Populate the message with the security layer, client supported receive + message size and authorization identity including the 0x00 based + terminator. Note: Dispite RFC4752 Section 3.1 stating "The authorization + identity is not terminated with the zero-valued (%x00) octet." it seems + necessary to include it. */ + outdata = htonl(max_size) | sec_layer; + memcpy(message, &outdata, sizeof(outdata)); + memcpy(message + sizeof(outdata), username_token.value, + username_token.length); + message[messagelen - 1] = '\0'; + + /* Free the username token as it is not required anymore */ + gss_release_buffer(&gss_status, &username_token); + + /* Setup the "authentication data" security buffer */ + input_token.value = message; + input_token.length = messagelen; + + /* Encrypt the data */ + gss_major_status = gss_wrap(&gss_minor_status, krb5->context, 0, + GSS_C_QOP_DEFAULT, &input_token, NULL, + &output_token); + if(GSS_ERROR(gss_major_status)) { + Curl_gss_log_error(data, gss_minor_status, "gss_wrap() failed: "); + + free(message); + + return CURLE_OUT_OF_MEMORY; + } + + /* Base64 encode the response */ + result = Curl_base64_encode(data, (char *) output_token.value, + output_token.length, outptr, outlen); + + /* Free the output buffer */ + gss_release_buffer(&gss_status, &output_token); + + /* Free the message buffer */ + free(message); + + return result; +} + +/* + * Curl_sasl_gssapi_cleanup() + * + * This is used to clean up the gssapi specific data. + * + * Parameters: + * + * krb5 [in/out] - The kerberos 5 data struct being cleaned up. + * + */ +void Curl_sasl_gssapi_cleanup(struct kerberos5data *krb5) +{ + OM_uint32 minor_status; + + /* Free our security context */ + if(krb5->context != GSS_C_NO_CONTEXT) { + gss_delete_sec_context(&minor_status, &krb5->context, GSS_C_NO_BUFFER); + krb5->context = GSS_C_NO_CONTEXT; + } + + /* Free the SPN */ + if(krb5->spn != GSS_C_NO_NAME) { + gss_release_name(&minor_status, &krb5->spn); + krb5->spn = GSS_C_NO_NAME; + } +} + +#endif /* HAVE_GSSAPI && USE_KERBEROS5 */ diff --git a/Utilities/cmcurl/lib/curl_sasl_sspi.c b/Utilities/cmcurl/lib/curl_sasl_sspi.c index df4da96..b149530 100644 --- a/Utilities/cmcurl/lib/curl_sasl_sspi.c +++ b/Utilities/cmcurl/lib/curl_sasl_sspi.c @@ -5,8 +5,8 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * + * Copyright (C) 2014 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * Copyright (C) 2014, Steve Holme, <steve_holme@hotmail.com>. - * Copyright (C) 2014, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -19,6 +19,7 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * RFC2617 Basic and Digest Access Authentication * RFC2831 DIGEST-MD5 authentication * RFC4422 Simple Authentication and Security Layer (SASL) * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism @@ -35,17 +36,16 @@ #include "urldata.h" #include "curl_base64.h" #include "warnless.h" -#include "curl_memory.h" #include "curl_multibyte.h" +#include "sendf.h" +#include "strdup.h" +#include "curl_printf.h" +#include "rawstr.h" -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - -/* The last #include file should be: */ +/* The last #include files should be: */ +#include "curl_memory.h" #include "memdebug.h" -void Curl_sasl_gssapi_cleanup(struct kerberos5data *krb5); - /* * Curl_sasl_build_spn() * @@ -54,7 +54,7 @@ void Curl_sasl_gssapi_cleanup(struct kerberos5data *krb5); * Parameters: * * serivce [in] - The service type such as www, smtp, pop or imap. - * instance [in] - The instance name such as the host nme or realm. + * host [in] - The host name or realm. * * Returns a pointer to the newly allocated SPN. */ @@ -79,14 +79,13 @@ TCHAR *Curl_sasl_build_spn(const char *service, const char *host) /* Allocate our TCHAR based SPN */ tchar_spn = Curl_convert_UTF8_to_tchar(utf8_spn); if(!tchar_spn) { - Curl_safefree(utf8_spn); + free(utf8_spn); return NULL; } /* Release the UTF8 variant when operating with Unicode */ - if(utf8_spn != tchar_spn) - Curl_safefree(utf8_spn); + Curl_unicodefree(utf8_spn); /* Return our newly allocated SPN */ return tchar_spn; @@ -102,8 +101,8 @@ TCHAR *Curl_sasl_build_spn(const char *service, const char *host) * Parameters: * * data [in] - The session handle. - * chlg64 [in] - Pointer to the base64 encoded challenge message. - * userp [in] - The user name. + * chlg64 [in] - The base64 encoded challenge message. + * userp [in] - The user name in the format User or Domain\User. * passdwp [in] - The user's password. * service [in] - The service type such as www, smtp, pop or imap. * outptr [in/out] - The address where a pointer to newly allocated memory @@ -122,57 +121,54 @@ CURLcode Curl_sasl_create_digest_md5_message(struct SessionHandle *data, CURLcode result = CURLE_OK; TCHAR *spn = NULL; size_t chlglen = 0; - size_t resp_max = 0; - unsigned char *chlg = NULL; - unsigned char *resp = NULL; - CredHandle handle; - CtxtHandle ctx; + size_t token_max = 0; + unsigned char *input_token = NULL; + unsigned char *output_token = NULL; + CredHandle credentials; + CtxtHandle context; PSecPkgInfo SecurityPackage; SEC_WINNT_AUTH_IDENTITY identity; + SEC_WINNT_AUTH_IDENTITY *p_identity; SecBuffer chlg_buf; SecBuffer resp_buf; SecBufferDesc chlg_desc; SecBufferDesc resp_desc; SECURITY_STATUS status; unsigned long attrs; - TimeStamp tsDummy; /* For Windows 9x compatibility of SSPI calls */ + TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ /* Decode the base-64 encoded challenge message */ if(strlen(chlg64) && *chlg64 != '=') { - result = Curl_base64_decode(chlg64, &chlg, &chlglen); + result = Curl_base64_decode(chlg64, &input_token, &chlglen); if(result) return result; } /* Ensure we have a valid challenge message */ - if(!chlg) - return CURLE_BAD_CONTENT_ENCODING; + if(!input_token) { + infof(data, "DIGEST-MD5 handshake failure (empty challenge message)\n"); - /* Ensure we have some login credientials as DigestSSP cannot use the current - Windows user like NTLMSSP can */ - if(!userp || !*userp) { - Curl_safefree(chlg); - return CURLE_LOGIN_DENIED; + return CURLE_BAD_CONTENT_ENCODING; } /* Query the security package for DigestSSP */ - status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT("WDigest"), + status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST), &SecurityPackage); if(status != SEC_E_OK) { - Curl_safefree(chlg); + free(input_token); return CURLE_NOT_BUILT_IN; } - resp_max = SecurityPackage->cbMaxToken; + token_max = SecurityPackage->cbMaxToken; /* Release the package buffer as it is not required anymore */ s_pSecFn->FreeContextBuffer(SecurityPackage); /* Allocate our response buffer */ - resp = malloc(resp_max); - if(!resp) { - Curl_safefree(chlg); + output_token = malloc(token_max); + if(!output_token) { + free(input_token); return CURLE_OUT_OF_MEMORY; } @@ -180,36 +176,44 @@ CURLcode Curl_sasl_create_digest_md5_message(struct SessionHandle *data, /* Generate our SPN */ spn = Curl_sasl_build_spn(service, data->easy_conn->host.name); if(!spn) { - Curl_safefree(resp); - Curl_safefree(chlg); + free(output_token); + free(input_token); return CURLE_OUT_OF_MEMORY; } - /* Populate our identity structure */ - result = Curl_create_sspi_identity(userp, passwdp, &identity); - if(result) { - Curl_safefree(spn); - Curl_safefree(resp); - Curl_safefree(chlg); + if(userp && *userp) { + /* Populate our identity structure */ + result = Curl_create_sspi_identity(userp, passwdp, &identity); + if(result) { + free(spn); + free(output_token); + free(input_token); + + return result; + } - return result; + /* Allow proper cleanup of the identity structure */ + p_identity = &identity; } + else + /* Use the current Windows user */ + p_identity = NULL; - /* Acquire our credientials handle */ + /* Acquire our credentials handle */ status = s_pSecFn->AcquireCredentialsHandle(NULL, - (TCHAR *) TEXT("WDigest"), + (TCHAR *) TEXT(SP_NAME_DIGEST), SECPKG_CRED_OUTBOUND, NULL, - &identity, NULL, NULL, - &handle, &tsDummy); + p_identity, NULL, NULL, + &credentials, &expiry); if(status != SEC_E_OK) { - Curl_sspi_free_identity(&identity); - Curl_safefree(spn); - Curl_safefree(resp); - Curl_safefree(chlg); + Curl_sspi_free_identity(p_identity); + free(spn); + free(output_token); + free(input_token); - return CURLE_OUT_OF_MEMORY; + return CURLE_LOGIN_DENIED; } /* Setup the challenge "input" security buffer */ @@ -217,7 +221,7 @@ CURLcode Curl_sasl_create_digest_md5_message(struct SessionHandle *data, chlg_desc.cBuffers = 1; chlg_desc.pBuffers = &chlg_buf; chlg_buf.BufferType = SECBUFFER_TOKEN; - chlg_buf.pvBuffer = chlg; + chlg_buf.pvBuffer = input_token; chlg_buf.cbBuffer = curlx_uztoul(chlglen); /* Setup the response "output" security buffer */ @@ -225,52 +229,611 @@ CURLcode Curl_sasl_create_digest_md5_message(struct SessionHandle *data, resp_desc.cBuffers = 1; resp_desc.pBuffers = &resp_buf; resp_buf.BufferType = SECBUFFER_TOKEN; - resp_buf.pvBuffer = resp; - resp_buf.cbBuffer = curlx_uztoul(resp_max); - - /* Generate our challenge-response message */ - status = s_pSecFn->InitializeSecurityContext(&handle, NULL, spn, 0, 0, 0, - &chlg_desc, 0, &ctx, - &resp_desc, &attrs, &tsDummy); - - if(status == SEC_I_COMPLETE_AND_CONTINUE || - status == SEC_I_CONTINUE_NEEDED) - s_pSecFn->CompleteAuthToken(&handle, &resp_desc); - else if(status != SEC_E_OK) { - s_pSecFn->FreeCredentialsHandle(&handle); - Curl_sspi_free_identity(&identity); - Curl_safefree(spn); - Curl_safefree(resp); - Curl_safefree(chlg); + resp_buf.pvBuffer = output_token; + resp_buf.cbBuffer = curlx_uztoul(token_max); + + /* Generate our response message */ + status = s_pSecFn->InitializeSecurityContext(&credentials, NULL, spn, + 0, 0, 0, &chlg_desc, 0, + &context, &resp_desc, &attrs, + &expiry); + + if(status == SEC_I_COMPLETE_NEEDED || + status == SEC_I_COMPLETE_AND_CONTINUE) + s_pSecFn->CompleteAuthToken(&credentials, &resp_desc); + else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) { + s_pSecFn->FreeCredentialsHandle(&credentials); + Curl_sspi_free_identity(p_identity); + free(spn); + free(output_token); + free(input_token); return CURLE_RECV_ERROR; } /* Base64 encode the response */ - result = Curl_base64_encode(data, (char *)resp, resp_buf.cbBuffer, outptr, - outlen); + result = Curl_base64_encode(data, (char *) output_token, resp_buf.cbBuffer, + outptr, outlen); /* Free our handles */ - s_pSecFn->DeleteSecurityContext(&ctx); - s_pSecFn->FreeCredentialsHandle(&handle); + s_pSecFn->DeleteSecurityContext(&context); + s_pSecFn->FreeCredentialsHandle(&credentials); /* Free the identity structure */ - Curl_sspi_free_identity(&identity); + Curl_sspi_free_identity(p_identity); /* Free the SPN */ - Curl_safefree(spn); + free(spn); /* Free the response buffer */ - Curl_safefree(resp); + free(output_token); - /* Free the decoeded challenge message */ - Curl_safefree(chlg); + /* Free the decoded challenge message */ + free(input_token); return result; } +/* +* Curl_override_sspi_http_realm() +* +* This is used to populate the domain in a SSPI identity structure +* The realm is extracted from the challenge message and used as the +* domain if it is not already explicitly set. +* +* Parameters: +* +* chlg [in] - The challenge message. +* identity [in/out] - The identity structure. +* +* Returns CURLE_OK on success. +*/ +CURLcode Curl_override_sspi_http_realm(const char *chlg, + SEC_WINNT_AUTH_IDENTITY *identity) +{ + xcharp_u domain, dup_domain; + + /* If domain is blank or unset, check challenge message for realm */ + if(!identity->Domain || !identity->DomainLength) { + for(;;) { + char value[DIGEST_MAX_VALUE_LENGTH]; + char content[DIGEST_MAX_CONTENT_LENGTH]; + + /* Pass all additional spaces here */ + while(*chlg && ISSPACE(*chlg)) + chlg++; + + /* Extract a value=content pair */ + if(!Curl_sasl_digest_get_pair(chlg, value, content, &chlg)) { + if(Curl_raw_equal(value, "realm")) { + + /* Setup identity's domain and length */ + domain.tchar_ptr = Curl_convert_UTF8_to_tchar((char *)content); + if(!domain.tchar_ptr) + return CURLE_OUT_OF_MEMORY; + dup_domain.tchar_ptr = _tcsdup(domain.tchar_ptr); + if(!dup_domain.tchar_ptr) { + Curl_unicodefree(domain.tchar_ptr); + return CURLE_OUT_OF_MEMORY; + } + identity->Domain = dup_domain.tbyte_ptr; + identity->DomainLength = curlx_uztoul(_tcslen(dup_domain.tchar_ptr)); + dup_domain.tchar_ptr = NULL; + + Curl_unicodefree(domain.tchar_ptr); + } + else { + /* unknown specifier, ignore it! */ + } + } + else + break; /* we're done here */ + + /* Pass all additional spaces here */ + while(*chlg && ISSPACE(*chlg)) + chlg++; + + /* Allow the list to be comma-separated */ + if(',' == *chlg) + chlg++; + } + } + + return CURLE_OK; +} + +/* + * Curl_sasl_decode_digest_http_message() + * + * This is used to decode a HTTP DIGEST challenge message into the seperate + * attributes. + * + * Parameters: + * + * chlg [in] - The challenge message. + * digest [in/out] - The digest data struct being used and modified. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_sasl_decode_digest_http_message(const char *chlg, + struct digestdata *digest) +{ + size_t chlglen = strlen(chlg); + + /* We had an input token before and we got another one now. This means we + provided bad credentials in the previous request. */ + if(digest->input_token) + return CURLE_BAD_CONTENT_ENCODING; + + /* Simply store the challenge for use later */ + digest->input_token = (BYTE *) Curl_memdup(chlg, chlglen); + if(!digest->input_token) + return CURLE_OUT_OF_MEMORY; + + digest->input_token_len = chlglen; + + return CURLE_OK; +} + +/* + * Curl_sasl_create_digest_http_message() + * + * This is used to generate a HTTP DIGEST response message ready for sending + * to the recipient. + * + * Parameters: + * + * data [in] - The session handle. + * userp [in] - The user name in the format User or Domain\User. + * passdwp [in] - The user's password. + * request [in] - The HTTP request. + * uripath [in] - The path of the HTTP uri. + * digest [in/out] - The digest data struct being used and modified. + * outptr [in/out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_sasl_create_digest_http_message(struct SessionHandle *data, + const char *userp, + const char *passwdp, + const unsigned char *request, + const unsigned char *uripath, + struct digestdata *digest, + char **outptr, size_t *outlen) +{ + size_t token_max; + CredHandle credentials; + CtxtHandle context; + char *resp; + BYTE *output_token; + PSecPkgInfo SecurityPackage; + SEC_WINNT_AUTH_IDENTITY identity; + SEC_WINNT_AUTH_IDENTITY *p_identity; + SecBuffer chlg_buf[3]; + SecBuffer resp_buf; + SecBufferDesc chlg_desc; + SecBufferDesc resp_desc; + SECURITY_STATUS status; + unsigned long attrs; + TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ + + (void) data; + + /* Query the security package for DigestSSP */ + status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST), + &SecurityPackage); + if(status != SEC_E_OK) + return CURLE_NOT_BUILT_IN; + + token_max = SecurityPackage->cbMaxToken; + + /* Release the package buffer as it is not required anymore */ + s_pSecFn->FreeContextBuffer(SecurityPackage); + + /* Allocate the output buffer according to the max token size as indicated + by the security package */ + output_token = malloc(token_max); + if(!output_token) + return CURLE_OUT_OF_MEMORY; + + if(userp && *userp) { + /* Populate our identity structure */ + if(Curl_create_sspi_identity(userp, passwdp, &identity)) + return CURLE_OUT_OF_MEMORY; + + /* Populate our identity domain */ + if(Curl_override_sspi_http_realm((const char*)digest->input_token, + &identity)) + return CURLE_OUT_OF_MEMORY; + + /* Allow proper cleanup of the identity structure */ + p_identity = &identity; + } + else + /* Use the current Windows user */ + p_identity = NULL; + + /* Acquire our credentials handle */ + status = s_pSecFn->AcquireCredentialsHandle(NULL, + (TCHAR *) TEXT(SP_NAME_DIGEST), + SECPKG_CRED_OUTBOUND, NULL, + p_identity, NULL, NULL, + &credentials, &expiry); + if(status != SEC_E_OK) { + free(output_token); + + return CURLE_LOGIN_DENIED; + } + + /* Setup the challenge "input" security buffer if present */ + chlg_desc.ulVersion = SECBUFFER_VERSION; + chlg_desc.cBuffers = 3; + chlg_desc.pBuffers = chlg_buf; + chlg_buf[0].BufferType = SECBUFFER_TOKEN; + chlg_buf[0].pvBuffer = digest->input_token; + chlg_buf[0].cbBuffer = curlx_uztoul(digest->input_token_len); + chlg_buf[1].BufferType = SECBUFFER_PKG_PARAMS; + chlg_buf[1].pvBuffer = (void *)request; + chlg_buf[1].cbBuffer = curlx_uztoul(strlen((const char *) request)); + chlg_buf[2].BufferType = SECBUFFER_PKG_PARAMS; + chlg_buf[2].pvBuffer = NULL; + chlg_buf[2].cbBuffer = 0; + + /* Setup the response "output" security buffer */ + resp_desc.ulVersion = SECBUFFER_VERSION; + resp_desc.cBuffers = 1; + resp_desc.pBuffers = &resp_buf; + resp_buf.BufferType = SECBUFFER_TOKEN; + resp_buf.pvBuffer = output_token; + resp_buf.cbBuffer = curlx_uztoul(token_max); + + /* Generate our reponse message */ + status = s_pSecFn->InitializeSecurityContext(&credentials, NULL, + (TCHAR *) uripath, + ISC_REQ_USE_HTTP_STYLE, 0, 0, + &chlg_desc, 0, &context, + &resp_desc, &attrs, &expiry); + + if(status == SEC_I_COMPLETE_NEEDED || + status == SEC_I_COMPLETE_AND_CONTINUE) + s_pSecFn->CompleteAuthToken(&credentials, &resp_desc); + else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) { + s_pSecFn->FreeCredentialsHandle(&credentials); + + free(output_token); + + return CURLE_OUT_OF_MEMORY; + } + + resp = malloc(resp_buf.cbBuffer + 1); + if(!resp) { + s_pSecFn->DeleteSecurityContext(&context); + s_pSecFn->FreeCredentialsHandle(&credentials); + + free(output_token); + + return CURLE_OUT_OF_MEMORY; + } + + /* Copy the generated reponse */ + memcpy(resp, resp_buf.pvBuffer, resp_buf.cbBuffer); + resp[resp_buf.cbBuffer] = 0x00; + + /* Return the response */ + *outptr = resp; + *outlen = resp_buf.cbBuffer; + + /* Free our handles */ + s_pSecFn->DeleteSecurityContext(&context); + s_pSecFn->FreeCredentialsHandle(&credentials); + + /* Free the identity structure */ + Curl_sspi_free_identity(p_identity); + + /* Free the response buffer */ + free(output_token); + + return CURLE_OK; +} + +/* + * Curl_sasl_digest_cleanup() + * + * This is used to clean up the digest specific data. + * + * Parameters: + * + * digest [in/out] - The digest data struct being cleaned up. + * + */ +void Curl_sasl_digest_cleanup(struct digestdata *digest) +{ + /* Free the input token */ + Curl_safefree(digest->input_token); + + /* Reset any variables */ + digest->input_token_len = 0; +} #endif /* !CURL_DISABLE_CRYPTO_AUTH */ +#if defined USE_NTLM +/* +* Curl_sasl_create_ntlm_type1_message() +* +* This is used to generate an already encoded NTLM type-1 message ready for +* sending to the recipient. +* +* Parameters: +* +* 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. +* outptr [in/out] - The address where a pointer to newly allocated memory +* holding the result will be stored upon completion. +* outlen [out] - The length of the output message. +* +* Returns CURLE_OK on success. +*/ +CURLcode Curl_sasl_create_ntlm_type1_message(const char *userp, + const char *passwdp, + struct ntlmdata *ntlm, + char **outptr, size_t *outlen) +{ + PSecPkgInfo SecurityPackage; + SecBuffer type_1_buf; + SecBufferDesc type_1_desc; + SECURITY_STATUS status; + unsigned long attrs; + TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ + + /* Clean up any former leftovers and initialise to defaults */ + Curl_sasl_ntlm_cleanup(ntlm); + + /* Query the security package for NTLM */ + status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_NTLM), + &SecurityPackage); + if(status != SEC_E_OK) + return CURLE_NOT_BUILT_IN; + + ntlm->token_max = SecurityPackage->cbMaxToken; + + /* Release the package buffer as it is not required anymore */ + s_pSecFn->FreeContextBuffer(SecurityPackage); + + /* Allocate our output buffer */ + ntlm->output_token = malloc(ntlm->token_max); + if(!ntlm->output_token) + return CURLE_OUT_OF_MEMORY; + + if(userp && *userp) { + CURLcode result; + + /* Populate our identity structure */ + result = Curl_create_sspi_identity(userp, passwdp, &ntlm->identity); + if(result) + return result; + + /* Allow proper cleanup of the identity structure */ + ntlm->p_identity = &ntlm->identity; + } + else + /* Use the current Windows user */ + ntlm->p_identity = NULL; + + /* Allocate our credentials handle */ + ntlm->credentials = malloc(sizeof(CredHandle)); + if(!ntlm->credentials) + return CURLE_OUT_OF_MEMORY; + + memset(ntlm->credentials, 0, sizeof(CredHandle)); + + /* Acquire our credentials handle */ + status = s_pSecFn->AcquireCredentialsHandle(NULL, + (TCHAR *) TEXT(SP_NAME_NTLM), + SECPKG_CRED_OUTBOUND, NULL, + ntlm->p_identity, NULL, NULL, + ntlm->credentials, &expiry); + if(status != SEC_E_OK) + return CURLE_LOGIN_DENIED; + + /* Allocate our new context handle */ + ntlm->context = malloc(sizeof(CtxtHandle)); + if(!ntlm->context) + return CURLE_OUT_OF_MEMORY; + + memset(ntlm->context, 0, sizeof(CtxtHandle)); + + /* Setup the type-1 "output" security buffer */ + type_1_desc.ulVersion = SECBUFFER_VERSION; + type_1_desc.cBuffers = 1; + type_1_desc.pBuffers = &type_1_buf; + type_1_buf.BufferType = SECBUFFER_TOKEN; + type_1_buf.pvBuffer = ntlm->output_token; + type_1_buf.cbBuffer = curlx_uztoul(ntlm->token_max); + + /* Generate our type-1 message */ + status = s_pSecFn->InitializeSecurityContext(ntlm->credentials, NULL, + (TCHAR *) TEXT(""), + 0, 0, SECURITY_NETWORK_DREP, + NULL, 0, + ntlm->context, &type_1_desc, + &attrs, &expiry); + if(status == SEC_I_COMPLETE_NEEDED || + status == SEC_I_COMPLETE_AND_CONTINUE) + s_pSecFn->CompleteAuthToken(ntlm->context, &type_1_desc); + else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) + return CURLE_RECV_ERROR; + + /* Base64 encode the response */ + return Curl_base64_encode(NULL, (char *) ntlm->output_token, + type_1_buf.cbBuffer, outptr, outlen); +} + +/* +* Curl_sasl_decode_ntlm_type2_message() +* +* This is used to decode an already encoded NTLM type-2 message. +* +* Parameters: +* +* data [in] - The session handle. +* type2msg [in] - The base64 encoded type-2 message. +* ntlm [in/out] - The ntlm data struct being used and modified. +* +* Returns CURLE_OK on success. +*/ +CURLcode Curl_sasl_decode_ntlm_type2_message(struct SessionHandle *data, + const char *type2msg, + struct ntlmdata *ntlm) +{ + CURLcode result = CURLE_OK; + unsigned char *type2 = NULL; + size_t type2_len = 0; + +#if defined(CURL_DISABLE_VERBOSE_STRINGS) + (void) data; +#endif + + /* Decode the base-64 encoded type-2 message */ + if(strlen(type2msg) && *type2msg != '=') { + result = Curl_base64_decode(type2msg, &type2, &type2_len); + if(result) + return result; + } + + /* Ensure we have a valid type-2 message */ + if(!type2) { + infof(data, "NTLM handshake failure (empty type-2 message)\n"); + + return CURLE_BAD_CONTENT_ENCODING; + } + + /* Simply store the challenge for use later */ + ntlm->input_token = type2; + ntlm->input_token_len = type2_len; + + return result; +} + +/* +* Curl_sasl_create_ntlm_type3_message() +* +* This is used to generate an already encoded NTLM type-3 message ready for +* sending to the recipient. +* +* 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. +* outptr [in/out] - The address where a pointer to newly allocated memory +* holding the result will be stored upon completion. +* outlen [out] - The length of the output message. +* +* Returns CURLE_OK on success. +*/ +CURLcode Curl_sasl_create_ntlm_type3_message(struct SessionHandle *data, + const char *userp, + const char *passwdp, + struct ntlmdata *ntlm, + char **outptr, size_t *outlen) +{ + CURLcode result = CURLE_OK; + SecBuffer type_2_buf; + SecBuffer type_3_buf; + SecBufferDesc type_2_desc; + SecBufferDesc type_3_desc; + SECURITY_STATUS status; + unsigned long attrs; + TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ + + (void) passwdp; + (void) userp; + + /* Setup the type-2 "input" security buffer */ + type_2_desc.ulVersion = SECBUFFER_VERSION; + type_2_desc.cBuffers = 1; + type_2_desc.pBuffers = &type_2_buf; + type_2_buf.BufferType = SECBUFFER_TOKEN; + type_2_buf.pvBuffer = ntlm->input_token; + type_2_buf.cbBuffer = curlx_uztoul(ntlm->input_token_len); + + /* Setup the type-3 "output" security buffer */ + type_3_desc.ulVersion = SECBUFFER_VERSION; + type_3_desc.cBuffers = 1; + type_3_desc.pBuffers = &type_3_buf; + type_3_buf.BufferType = SECBUFFER_TOKEN; + type_3_buf.pvBuffer = ntlm->output_token; + type_3_buf.cbBuffer = curlx_uztoul(ntlm->token_max); + + /* Generate our type-3 message */ + status = s_pSecFn->InitializeSecurityContext(ntlm->credentials, + ntlm->context, + (TCHAR *) TEXT(""), + 0, 0, SECURITY_NETWORK_DREP, + &type_2_desc, + 0, ntlm->context, + &type_3_desc, + &attrs, &expiry); + if(status != SEC_E_OK) { + infof(data, "NTLM handshake failure (type-3 message): Status=%x\n", + status); + + return CURLE_RECV_ERROR; + } + + /* Base64 encode the response */ + result = Curl_base64_encode(data, (char *) ntlm->output_token, + type_3_buf.cbBuffer, outptr, outlen); + + Curl_sasl_ntlm_cleanup(ntlm); + + return result; +} + +/* + * Curl_sasl_ntlm_cleanup() + * + * This is used to clean up the ntlm specific data. + * + * Parameters: + * + * ntlm [in/out] - The ntlm data struct being cleaned up. + * + */ +void Curl_sasl_ntlm_cleanup(struct ntlmdata *ntlm) +{ + /* Free our security context */ + if(ntlm->context) { + s_pSecFn->DeleteSecurityContext(ntlm->context); + free(ntlm->context); + ntlm->context = NULL; + } + + /* Free our credentials handle */ + if(ntlm->credentials) { + s_pSecFn->FreeCredentialsHandle(ntlm->credentials); + free(ntlm->credentials); + ntlm->credentials = NULL; + } + + /* Free our identity */ + Curl_sspi_free_identity(ntlm->p_identity); + ntlm->p_identity = NULL; + + /* Free the input and output tokens */ + Curl_safefree(ntlm->input_token); + Curl_safefree(ntlm->output_token); + + /* Reset any variables */ + ntlm->token_max = 0; +} +#endif /* USE_NTLM */ + +#if defined(USE_KERBEROS5) /* * Curl_sasl_create_gssapi_user_message() * @@ -280,13 +843,12 @@ CURLcode Curl_sasl_create_digest_md5_message(struct SessionHandle *data, * Parameters: * * data [in] - The session handle. - * userp [in] - The user name. + * userp [in] - The user name in the format User or Domain\User. * passdwp [in] - The user's password. * service [in] - The service type such as www, smtp, pop or imap. * mutual_auth [in] - Flag specifing whether or not mutual authentication * is enabled. - * chlg64 [in] - Pointer to the optional base64 encoded challenge - * message. + * chlg64 [in] - The optional base64 encoded challenge message. * krb5 [in/out] - The gssapi data struct being used and modified. * outptr [in/out] - The address where a pointer to newly allocated memory * holding the result will be stored upon completion. @@ -314,11 +876,12 @@ CURLcode Curl_sasl_create_gssapi_user_message(struct SessionHandle *data, SecBufferDesc resp_desc; SECURITY_STATUS status; unsigned long attrs; - TimeStamp tsDummy; /* For Windows 9x compatibility of SSPI calls */ + TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ if(!krb5->credentials) { /* Query the security package for Kerberos */ - status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT("Kerberos"), + status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) + TEXT(SP_NAME_KERBEROS), &SecurityPackage); if(status != SEC_E_OK) { return CURLE_NOT_BUILT_IN; @@ -329,6 +892,11 @@ CURLcode Curl_sasl_create_gssapi_user_message(struct SessionHandle *data, /* Release the package buffer as it is not required anymore */ s_pSecFn->FreeContextBuffer(SecurityPackage); + /* Allocate our response buffer */ + krb5->output_token = malloc(krb5->token_max); + if(!krb5->output_token) + return CURLE_OUT_OF_MEMORY; + /* Generate our SPN */ krb5->spn = Curl_sasl_build_spn(service, data->easy_conn->host.name); if(!krb5->spn) @@ -342,11 +910,6 @@ CURLcode Curl_sasl_create_gssapi_user_message(struct SessionHandle *data, /* Allow proper cleanup of the identity structure */ krb5->p_identity = &krb5->identity; - - /* Allocate our response buffer */ - krb5->output_token = malloc(krb5->token_max); - if(!krb5->output_token) - return CURLE_OUT_OF_MEMORY; } else /* Use the current Windows user */ @@ -359,14 +922,15 @@ CURLcode Curl_sasl_create_gssapi_user_message(struct SessionHandle *data, memset(krb5->credentials, 0, sizeof(CredHandle)); - /* Acquire our credientials handle */ + /* Acquire our credentials handle */ status = s_pSecFn->AcquireCredentialsHandle(NULL, - (TCHAR *) TEXT("Kerberos"), + (TCHAR *) + TEXT(SP_NAME_KERBEROS), SECPKG_CRED_OUTBOUND, NULL, krb5->p_identity, NULL, NULL, - krb5->credentials, &tsDummy); + krb5->credentials, &expiry); if(status != SEC_E_OK) - return CURLE_OUT_OF_MEMORY; + return CURLE_LOGIN_DENIED; /* Allocate our new context handle */ krb5->context = malloc(sizeof(CtxtHandle)); @@ -384,8 +948,11 @@ CURLcode Curl_sasl_create_gssapi_user_message(struct SessionHandle *data, } /* Ensure we have a valid challenge message */ - if(!chlg) + if(!chlg) { + infof(data, "GSSAPI handshake failure (empty challenge message)\n"); + return CURLE_BAD_CONTENT_ENCODING; + } /* Setup the challenge "input" security buffer */ chlg_desc.ulVersion = SECBUFFER_VERSION; @@ -414,10 +981,10 @@ CURLcode Curl_sasl_create_gssapi_user_message(struct SessionHandle *data, chlg ? &chlg_desc : NULL, 0, &context, &resp_desc, &attrs, - &tsDummy); + &expiry); if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) { - Curl_safefree(chlg); + free(chlg); return CURLE_RECV_ERROR; } @@ -435,7 +1002,7 @@ CURLcode Curl_sasl_create_gssapi_user_message(struct SessionHandle *data, } /* Free the decoded challenge */ - Curl_safefree(chlg); + free(chlg); return result; } @@ -449,7 +1016,7 @@ CURLcode Curl_sasl_create_gssapi_user_message(struct SessionHandle *data, * Parameters: * * data [in] - The session handle. - * chlg64 [in] - Pointer to the optional base64 encoded challenge message. + * chlg64 [in] - The optional base64 encoded challenge message. * krb5 [in/out] - The gssapi data struct being used and modified. * outptr [in/out] - The address where a pointer to newly allocated memory * holding the result will be stored upon completion. @@ -485,8 +1052,7 @@ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data, SecPkgContext_Sizes sizes; SecPkgCredentials_Names names; SECURITY_STATUS status; - - /* TODO: Verify the unicodeness of this function */ + char *user_name; /* Decode the base-64 encoded input message */ if(strlen(chlg64) && *chlg64 != '=') { @@ -496,15 +1062,18 @@ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data, } /* Ensure we have a valid challenge message */ - if(!chlg) + if(!chlg) { + infof(data, "GSSAPI handshake failure (empty security message)\n"); + return CURLE_BAD_CONTENT_ENCODING; + } /* Get our response size information */ status = s_pSecFn->QueryContextAttributes(krb5->context, SECPKG_ATTR_SIZES, &sizes); if(status != SEC_E_OK) { - Curl_safefree(chlg); + free(chlg); return CURLE_OUT_OF_MEMORY; } @@ -514,7 +1083,7 @@ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data, SECPKG_CRED_ATTR_NAMES, &names); if(status != SEC_E_OK) { - Curl_safefree(chlg); + free(chlg); return CURLE_RECV_ERROR; } @@ -530,30 +1099,34 @@ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data, input_buf[1].pvBuffer = NULL; input_buf[1].cbBuffer = 0; - /* Decrypt in the inbound challenge obtaining the qop */ + /* Decrypt the inbound challenge and obtain the qop */ status = s_pSecFn->DecryptMessage(krb5->context, &input_desc, 0, &qop); if(status != SEC_E_OK) { - Curl_safefree(chlg); + infof(data, "GSSAPI handshake failure (empty security message)\n"); + + free(chlg); return CURLE_BAD_CONTENT_ENCODING; } - /* Not 4 octets long to fail as per RFC4752 Section 3.1 */ + /* Not 4 octets long so fail as per RFC4752 Section 3.1 */ if(input_buf[1].cbBuffer != 4) { - Curl_safefree(chlg); + infof(data, "GSSAPI handshake failure (invalid security data)\n"); + + free(chlg); return CURLE_BAD_CONTENT_ENCODING; } - /* Copy the data out into a coinput_bufnvenient variable and free the SSPI - allocated buffer as it is not required anymore */ + /* Copy the data out and free the challenge as it is not required anymore */ memcpy(&indata, input_buf[1].pvBuffer, 4); s_pSecFn->FreeContextBuffer(input_buf[1].pvBuffer); + free(chlg); /* Extract the security layer */ sec_layer = indata & 0x000000FF; if(!(sec_layer & KERB_WRAP_NO_ENCRYPT)) { - Curl_safefree(chlg); + infof(data, "GSSAPI handshake failure (invalid security layer)\n"); return CURLE_BAD_CONTENT_ENCODING; } @@ -562,27 +1135,30 @@ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data, max_size = ntohl(indata & 0xFFFFFF00); if(max_size > 0) { /* The server has told us it supports a maximum receive buffer, however, as - we don't require one unless we are encrypting data we, tell the server + we don't require one unless we are encrypting data, we tell the server our receive buffer is zero. */ max_size = 0; } - outdata = htonl(max_size) | sec_layer; - /* Allocate the trailer */ trailer = malloc(sizes.cbSecurityTrailer); - if(!trailer) { - Curl_safefree(chlg); + if(!trailer) + return CURLE_OUT_OF_MEMORY; + + /* Convert the user name to UTF8 when operating with Unicode */ + user_name = Curl_convert_tchar_to_UTF8(names.sUserName); + if(!user_name) { + free(trailer); return CURLE_OUT_OF_MEMORY; } /* Allocate our message */ - messagelen = 4 + strlen(names.sUserName) + 1; + messagelen = sizeof(outdata) + strlen(user_name) + 1; message = malloc(messagelen); if(!message) { - Curl_safefree(trailer); - Curl_safefree(chlg); + free(trailer); + Curl_unicodefree(user_name); return CURLE_OUT_OF_MEMORY; } @@ -592,15 +1168,16 @@ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data, terminator. Note: Dispite RFC4752 Section 3.1 stating "The authorization identity is not terminated with the zero-valued (%x00) octet." it seems necessary to include it. */ - memcpy(message, &outdata, 4); - strcpy((char *)message + 4, names.sUserName); + outdata = htonl(max_size) | sec_layer; + memcpy(message, &outdata, sizeof(outdata)); + strcpy((char *) message + sizeof(outdata), user_name); + Curl_unicodefree(user_name); /* Allocate the padding */ padding = malloc(sizes.cbBlockSize); if(!padding) { - Curl_safefree(message); - Curl_safefree(trailer); - Curl_safefree(chlg); + free(message); + free(trailer); return CURLE_OUT_OF_MEMORY; } @@ -623,10 +1200,9 @@ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data, status = s_pSecFn->EncryptMessage(krb5->context, KERB_WRAP_NO_ENCRYPT, &wrap_desc, 0); if(status != SEC_E_OK) { - Curl_safefree(padding); - Curl_safefree(message); - Curl_safefree(trailer); - Curl_safefree(chlg); + free(padding); + free(message); + free(trailer); return CURLE_OUT_OF_MEMORY; } @@ -636,10 +1212,9 @@ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data, wrap_buf[2].cbBuffer; appdata = malloc(appdatalen); if(!appdata) { - Curl_safefree(padding); - Curl_safefree(message); - Curl_safefree(trailer); - Curl_safefree(chlg); + free(padding); + free(message); + free(trailer); return CURLE_OUT_OF_MEMORY; } @@ -656,25 +1231,34 @@ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data, outlen); /* Free all of our local buffers */ - Curl_safefree(appdata); - Curl_safefree(padding); - Curl_safefree(message); - Curl_safefree(trailer); - Curl_safefree(chlg); + free(appdata); + free(padding); + free(message); + free(trailer); return result; } +/* + * Curl_sasl_gssapi_cleanup() + * + * This is used to clean up the gssapi specific data. + * + * Parameters: + * + * krb5 [in/out] - The kerberos 5 data struct being cleaned up. + * + */ void Curl_sasl_gssapi_cleanup(struct kerberos5data *krb5) { - /* Free the context */ + /* Free our security context */ if(krb5->context) { s_pSecFn->DeleteSecurityContext(krb5->context); free(krb5->context); krb5->context = NULL; } - /* Free the credientials handle */ + /* Free our credentials handle */ if(krb5->credentials) { s_pSecFn->FreeCredentialsHandle(krb5->credentials); free(krb5->credentials); @@ -692,5 +1276,6 @@ void Curl_sasl_gssapi_cleanup(struct kerberos5data *krb5) /* Reset any variables */ krb5->token_max = 0; } +#endif /* USE_KERBEROS5 */ #endif /* USE_WINDOWS_SSPI */ diff --git a/Utilities/cmcurl/lib/curl_sec.h b/Utilities/cmcurl/lib/curl_sec.h index 82151e9..6c48da2 100644 --- a/Utilities/cmcurl/lib/curl_sec.h +++ b/Utilities/cmcurl/lib/curl_sec.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -30,7 +30,7 @@ struct Curl_sec_client_mech { void (*end)(void *); int (*check_prot)(void *, int); int (*overhead)(void *, int, int); - int (*encode)(void *, const void*, int, int, void**, struct connectdata *); + int (*encode)(void *, const void*, int, int, void**); int (*decode)(void *, void*, int, int, struct connectdata *); }; diff --git a/Utilities/cmcurl/lib/curl_setup.h b/Utilities/cmcurl/lib/curl_setup.h index 9cc5758..19c1baf 100644 --- a/Utilities/cmcurl/lib/curl_setup.h +++ b/Utilities/cmcurl/lib/curl_setup.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -194,6 +194,9 @@ # ifndef CURL_DISABLE_GOPHER # define CURL_DISABLE_GOPHER # endif +# ifndef CURL_DISABLE_SMB +# define CURL_DISABLE_SMB +# endif #endif /* @@ -616,26 +619,38 @@ int netware_init(void); #define LIBIDN_REQUIRED_VERSION "0.4.1" -#if defined(USE_GNUTLS) || defined(USE_SSLEAY) || defined(USE_NSS) || \ - defined(USE_QSOSSL) || defined(USE_POLARSSL) || defined(USE_AXTLS) || \ +#if defined(USE_GNUTLS) || defined(USE_OPENSSL) || defined(USE_NSS) || \ + defined(USE_POLARSSL) || defined(USE_AXTLS) || \ defined(USE_CYASSL) || defined(USE_SCHANNEL) || \ defined(USE_DARWINSSL) || defined(USE_GSKIT) #define USE_SSL /* SSL support has been enabled */ #endif +/* Single point where USE_SPNEGO definition might be defined */ #if !defined(CURL_DISABLE_CRYPTO_AUTH) && \ (defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)) #define USE_SPNEGO #endif -/* Single point where USE_NTLM definition might be done */ -#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_NTLM) && \ - !defined(CURL_DISABLE_CRYPTO_AUTH) -#if defined(USE_SSLEAY) || defined(USE_WINDOWS_SSPI) || \ - defined(USE_GNUTLS) || defined(USE_NSS) || defined(USE_DARWINSSL) +/* Single point where USE_KERBEROS5 definition might be defined */ +#if !defined(CURL_DISABLE_CRYPTO_AUTH) && \ + (defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)) +#define USE_KERBEROS5 +#endif + +/* Single point where USE_NTLM definition might be defined */ +#if !defined(CURL_DISABLE_NTLM) && !defined(CURL_DISABLE_CRYPTO_AUTH) +#if defined(USE_OPENSSL) || defined(USE_WINDOWS_SSPI) || \ + defined(USE_GNUTLS) || defined(USE_NSS) || defined(USE_DARWINSSL) || \ + defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO) + +#ifdef HAVE_BORINGSSL /* BoringSSL is not NTLM capable */ +#undef USE_NTLM +#else #define USE_NTLM #endif #endif +#endif /* non-configure builds may define CURL_WANTS_CA_BUNDLE_ENV */ #if defined(CURL_WANTS_CA_BUNDLE_ENV) && !defined(CURL_CA_BUNDLE) @@ -651,8 +666,10 @@ int netware_init(void); #if defined(__GNUC__) && ((__GNUC__ >= 3) || \ ((__GNUC__ == 2) && defined(__GNUC_MINOR__) && (__GNUC_MINOR__ >= 7))) # define UNUSED_PARAM __attribute__((__unused__)) +# define WARN_UNUSED_RESULT __attribute__((warn_unused_result)) #else # define UNUSED_PARAM /*NOTHING*/ +# define WARN_UNUSED_RESULT #endif /* @@ -705,4 +722,24 @@ int netware_init(void); #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) #endif +/* In Windows the default file mode is text but an application can override it. +Therefore we specify it explicitly. https://github.com/bagder/curl/pull/258 +*/ +#if defined(WIN32) || defined(MSDOS) +#define FOPEN_READTEXT "rt" +#define FOPEN_WRITETEXT "wt" +#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 +For write we want our output to have line endings of LF and be compatible with +other Cygwin utilities. For read we want to handle input that may have line +endings either CRLF or LF so 't' is appropriate. +*/ +#define FOPEN_READTEXT "rt" +#define FOPEN_WRITETEXT "w" +#else +#define FOPEN_READTEXT "r" +#define FOPEN_WRITETEXT "w" +#endif + #endif /* HEADER_CURL_SETUP_H */ diff --git a/Utilities/cmcurl/lib/curl_sspi.c b/Utilities/cmcurl/lib/curl_sspi.c index f09d288..070424d 100644 --- a/Utilities/cmcurl/lib/curl_sspi.c +++ b/Utilities/cmcurl/lib/curl_sspi.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -25,17 +25,12 @@ #ifdef USE_WINDOWS_SSPI #include <curl/curl.h> - #include "curl_sspi.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - -#include "curl_memory.h" #include "curl_multibyte.h" #include "warnless.h" -/* The last #include file should be: */ +/* The last #include files should be: */ +#include "curl_memory.h" #include "memdebug.h" /* We use our own typedef here since some headers might lack these */ @@ -98,20 +93,25 @@ CURLcode Curl_sspi_global_init(void) osver.dwPlatformId == platformId) securityDll = TRUE; #else - ULONGLONG majorVersionMask; - ULONGLONG platformIdMask; + ULONGLONG cm; OSVERSIONINFOEX osver; memset(&osver, 0, sizeof(osver)); osver.dwOSVersionInfoSize = sizeof(osver); osver.dwMajorVersion = majorVersion; osver.dwPlatformId = platformId; - majorVersionMask = VerSetConditionMask(0, VER_MAJORVERSION, VER_EQUAL); - platformIdMask = VerSetConditionMask(0, VER_PLATFORMID, VER_EQUAL); + + cm = VerSetConditionMask(0, VER_MAJORVERSION, VER_EQUAL); + cm = VerSetConditionMask(cm, VER_MINORVERSION, VER_GREATER_EQUAL); + cm = VerSetConditionMask(cm, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL); + cm = VerSetConditionMask(cm, VER_SERVICEPACKMINOR, VER_GREATER_EQUAL); + cm = VerSetConditionMask(cm, VER_PLATFORMID, VER_EQUAL); /* Verify the major version number == 4 and platform id == WIN_NT */ - if(VerifyVersionInfo(&osver, VER_MAJORVERSION, majorVersionMask) && - VerifyVersionInfo(&osver, VER_PLATFORMID, platformIdMask)) + if(VerifyVersionInfo(&osver, (VER_MAJORVERSION | VER_MINORVERSION | + VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR | + VER_PLATFORMID), + cm)) securityDll = TRUE; #endif @@ -224,7 +224,7 @@ CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp, Curl_unicodefree(useranddomain.tchar_ptr); - /* Setup ntlm identity's password and length */ + /* Setup the identity's password and length */ passwd.tchar_ptr = Curl_convert_UTF8_to_tchar((char *)passwdp); if(!passwd.tchar_ptr) return CURLE_OUT_OF_MEMORY; diff --git a/Utilities/cmcurl/lib/curl_sspi.h b/Utilities/cmcurl/lib/curl_sspi.h index 5ab17d5..8655715 100644 --- a/Utilities/cmcurl/lib/curl_sspi.h +++ b/Utilities/cmcurl/lib/curl_sspi.h @@ -43,6 +43,10 @@ CURLcode Curl_sspi_global_init(void); void Curl_sspi_global_cleanup(void); +/* This is used to populate the domain in a SSPI identity structure */ +CURLcode Curl_override_sspi_http_realm(const char *chlg, + SEC_WINNT_AUTH_IDENTITY *identity); + /* This is used to generate an SSPI identity structure */ CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp, SEC_WINNT_AUTH_IDENTITY *identity); @@ -51,249 +55,276 @@ CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp, void Curl_sspi_free_identity(SEC_WINNT_AUTH_IDENTITY *identity); /* Forward-declaration of global variables defined in curl_sspi.c */ - extern HMODULE s_hSecDll; extern PSecurityFunctionTable s_pSecFn; /* Provide some definitions missing in old headers */ +#define SP_NAME_DIGEST "WDigest" +#define SP_NAME_NTLM "NTLM" +#define SP_NAME_NEGOTIATE "Negotiate" +#define SP_NAME_KERBEROS "Kerberos" + +#ifndef ISC_REQ_USE_HTTP_STYLE +#define ISC_REQ_USE_HTTP_STYLE 0x01000000 +#endif + +#ifndef ISC_RET_REPLAY_DETECT +#define ISC_RET_REPLAY_DETECT 0x00000004 +#endif + +#ifndef ISC_RET_SEQUENCE_DETECT +#define ISC_RET_SEQUENCE_DETECT 0x00000008 +#endif + +#ifndef ISC_RET_CONFIDENTIALITY +#define ISC_RET_CONFIDENTIALITY 0x00000010 +#endif + +#ifndef ISC_RET_ALLOCATED_MEMORY +#define ISC_RET_ALLOCATED_MEMORY 0x00000100 +#endif + +#ifndef ISC_RET_STREAM +#define ISC_RET_STREAM 0x00008000 +#endif #ifndef SEC_E_INSUFFICIENT_MEMORY -# define SEC_E_INSUFFICIENT_MEMORY ((HRESULT)0x80090300L) +# define SEC_E_INSUFFICIENT_MEMORY ((HRESULT)0x80090300L) #endif #ifndef SEC_E_INVALID_HANDLE -# define SEC_E_INVALID_HANDLE ((HRESULT)0x80090301L) +# define SEC_E_INVALID_HANDLE ((HRESULT)0x80090301L) #endif #ifndef SEC_E_UNSUPPORTED_FUNCTION -# define SEC_E_UNSUPPORTED_FUNCTION ((HRESULT)0x80090302L) +# define SEC_E_UNSUPPORTED_FUNCTION ((HRESULT)0x80090302L) #endif #ifndef SEC_E_TARGET_UNKNOWN -# define SEC_E_TARGET_UNKNOWN ((HRESULT)0x80090303L) +# define SEC_E_TARGET_UNKNOWN ((HRESULT)0x80090303L) #endif #ifndef SEC_E_INTERNAL_ERROR -# define SEC_E_INTERNAL_ERROR ((HRESULT)0x80090304L) +# define SEC_E_INTERNAL_ERROR ((HRESULT)0x80090304L) #endif #ifndef SEC_E_SECPKG_NOT_FOUND -# define SEC_E_SECPKG_NOT_FOUND ((HRESULT)0x80090305L) +# define SEC_E_SECPKG_NOT_FOUND ((HRESULT)0x80090305L) #endif #ifndef SEC_E_NOT_OWNER -# define SEC_E_NOT_OWNER ((HRESULT)0x80090306L) +# define SEC_E_NOT_OWNER ((HRESULT)0x80090306L) #endif #ifndef SEC_E_CANNOT_INSTALL -# define SEC_E_CANNOT_INSTALL ((HRESULT)0x80090307L) +# define SEC_E_CANNOT_INSTALL ((HRESULT)0x80090307L) #endif #ifndef SEC_E_INVALID_TOKEN -# define SEC_E_INVALID_TOKEN ((HRESULT)0x80090308L) +# define SEC_E_INVALID_TOKEN ((HRESULT)0x80090308L) #endif #ifndef SEC_E_CANNOT_PACK -# define SEC_E_CANNOT_PACK ((HRESULT)0x80090309L) +# define SEC_E_CANNOT_PACK ((HRESULT)0x80090309L) #endif #ifndef SEC_E_QOP_NOT_SUPPORTED -# define SEC_E_QOP_NOT_SUPPORTED ((HRESULT)0x8009030AL) +# define SEC_E_QOP_NOT_SUPPORTED ((HRESULT)0x8009030AL) #endif #ifndef SEC_E_NO_IMPERSONATION -# define SEC_E_NO_IMPERSONATION ((HRESULT)0x8009030BL) +# define SEC_E_NO_IMPERSONATION ((HRESULT)0x8009030BL) #endif #ifndef SEC_E_LOGON_DENIED -# define SEC_E_LOGON_DENIED ((HRESULT)0x8009030CL) +# define SEC_E_LOGON_DENIED ((HRESULT)0x8009030CL) #endif #ifndef SEC_E_UNKNOWN_CREDENTIALS -# define SEC_E_UNKNOWN_CREDENTIALS ((HRESULT)0x8009030DL) +# define SEC_E_UNKNOWN_CREDENTIALS ((HRESULT)0x8009030DL) #endif #ifndef SEC_E_NO_CREDENTIALS -# define SEC_E_NO_CREDENTIALS ((HRESULT)0x8009030EL) +# define SEC_E_NO_CREDENTIALS ((HRESULT)0x8009030EL) #endif #ifndef SEC_E_MESSAGE_ALTERED -# define SEC_E_MESSAGE_ALTERED ((HRESULT)0x8009030FL) +# define SEC_E_MESSAGE_ALTERED ((HRESULT)0x8009030FL) #endif #ifndef SEC_E_OUT_OF_SEQUENCE -# define SEC_E_OUT_OF_SEQUENCE ((HRESULT)0x80090310L) +# define SEC_E_OUT_OF_SEQUENCE ((HRESULT)0x80090310L) #endif #ifndef SEC_E_NO_AUTHENTICATING_AUTHORITY -# define SEC_E_NO_AUTHENTICATING_AUTHORITY ((HRESULT)0x80090311L) +# define SEC_E_NO_AUTHENTICATING_AUTHORITY ((HRESULT)0x80090311L) #endif #ifndef SEC_E_BAD_PKGID -# define SEC_E_BAD_PKGID ((HRESULT)0x80090316L) +# define SEC_E_BAD_PKGID ((HRESULT)0x80090316L) #endif #ifndef SEC_E_CONTEXT_EXPIRED -# define SEC_E_CONTEXT_EXPIRED ((HRESULT)0x80090317L) +# define SEC_E_CONTEXT_EXPIRED ((HRESULT)0x80090317L) #endif #ifndef SEC_E_INCOMPLETE_MESSAGE -# define SEC_E_INCOMPLETE_MESSAGE ((HRESULT)0x80090318L) +# define SEC_E_INCOMPLETE_MESSAGE ((HRESULT)0x80090318L) #endif #ifndef SEC_E_INCOMPLETE_CREDENTIALS -# define SEC_E_INCOMPLETE_CREDENTIALS ((HRESULT)0x80090320L) +# define SEC_E_INCOMPLETE_CREDENTIALS ((HRESULT)0x80090320L) #endif #ifndef SEC_E_BUFFER_TOO_SMALL -# define SEC_E_BUFFER_TOO_SMALL ((HRESULT)0x80090321L) +# define SEC_E_BUFFER_TOO_SMALL ((HRESULT)0x80090321L) #endif #ifndef SEC_E_WRONG_PRINCIPAL -# define SEC_E_WRONG_PRINCIPAL ((HRESULT)0x80090322L) +# define SEC_E_WRONG_PRINCIPAL ((HRESULT)0x80090322L) #endif #ifndef SEC_E_TIME_SKEW -# define SEC_E_TIME_SKEW ((HRESULT)0x80090324L) +# define SEC_E_TIME_SKEW ((HRESULT)0x80090324L) #endif #ifndef SEC_E_UNTRUSTED_ROOT -# define SEC_E_UNTRUSTED_ROOT ((HRESULT)0x80090325L) +# define SEC_E_UNTRUSTED_ROOT ((HRESULT)0x80090325L) #endif #ifndef SEC_E_ILLEGAL_MESSAGE -# define SEC_E_ILLEGAL_MESSAGE ((HRESULT)0x80090326L) +# define SEC_E_ILLEGAL_MESSAGE ((HRESULT)0x80090326L) #endif #ifndef SEC_E_CERT_UNKNOWN -# define SEC_E_CERT_UNKNOWN ((HRESULT)0x80090327L) +# define SEC_E_CERT_UNKNOWN ((HRESULT)0x80090327L) #endif #ifndef SEC_E_CERT_EXPIRED -# define SEC_E_CERT_EXPIRED ((HRESULT)0x80090328L) +# define SEC_E_CERT_EXPIRED ((HRESULT)0x80090328L) #endif #ifndef SEC_E_ENCRYPT_FAILURE -# define SEC_E_ENCRYPT_FAILURE ((HRESULT)0x80090329L) +# define SEC_E_ENCRYPT_FAILURE ((HRESULT)0x80090329L) #endif #ifndef SEC_E_DECRYPT_FAILURE -# define SEC_E_DECRYPT_FAILURE ((HRESULT)0x80090330L) +# define SEC_E_DECRYPT_FAILURE ((HRESULT)0x80090330L) #endif #ifndef SEC_E_ALGORITHM_MISMATCH -# define SEC_E_ALGORITHM_MISMATCH ((HRESULT)0x80090331L) +# define SEC_E_ALGORITHM_MISMATCH ((HRESULT)0x80090331L) #endif #ifndef SEC_E_SECURITY_QOS_FAILED -# define SEC_E_SECURITY_QOS_FAILED ((HRESULT)0x80090332L) +# define SEC_E_SECURITY_QOS_FAILED ((HRESULT)0x80090332L) #endif #ifndef SEC_E_UNFINISHED_CONTEXT_DELETED -# define SEC_E_UNFINISHED_CONTEXT_DELETED ((HRESULT)0x80090333L) +# define SEC_E_UNFINISHED_CONTEXT_DELETED ((HRESULT)0x80090333L) #endif #ifndef SEC_E_NO_TGT_REPLY -# define SEC_E_NO_TGT_REPLY ((HRESULT)0x80090334L) +# define SEC_E_NO_TGT_REPLY ((HRESULT)0x80090334L) #endif #ifndef SEC_E_NO_IP_ADDRESSES -# define SEC_E_NO_IP_ADDRESSES ((HRESULT)0x80090335L) +# define SEC_E_NO_IP_ADDRESSES ((HRESULT)0x80090335L) #endif #ifndef SEC_E_WRONG_CREDENTIAL_HANDLE -# define SEC_E_WRONG_CREDENTIAL_HANDLE ((HRESULT)0x80090336L) +# define SEC_E_WRONG_CREDENTIAL_HANDLE ((HRESULT)0x80090336L) #endif #ifndef SEC_E_CRYPTO_SYSTEM_INVALID -# define SEC_E_CRYPTO_SYSTEM_INVALID ((HRESULT)0x80090337L) +# define SEC_E_CRYPTO_SYSTEM_INVALID ((HRESULT)0x80090337L) #endif #ifndef SEC_E_MAX_REFERRALS_EXCEEDED -# define SEC_E_MAX_REFERRALS_EXCEEDED ((HRESULT)0x80090338L) +# define SEC_E_MAX_REFERRALS_EXCEEDED ((HRESULT)0x80090338L) #endif #ifndef SEC_E_MUST_BE_KDC -# define SEC_E_MUST_BE_KDC ((HRESULT)0x80090339L) +# define SEC_E_MUST_BE_KDC ((HRESULT)0x80090339L) #endif #ifndef SEC_E_STRONG_CRYPTO_NOT_SUPPORTED -# define SEC_E_STRONG_CRYPTO_NOT_SUPPORTED ((HRESULT)0x8009033AL) +# define SEC_E_STRONG_CRYPTO_NOT_SUPPORTED ((HRESULT)0x8009033AL) #endif #ifndef SEC_E_TOO_MANY_PRINCIPALS -# define SEC_E_TOO_MANY_PRINCIPALS ((HRESULT)0x8009033BL) +# define SEC_E_TOO_MANY_PRINCIPALS ((HRESULT)0x8009033BL) #endif #ifndef SEC_E_NO_PA_DATA -# define SEC_E_NO_PA_DATA ((HRESULT)0x8009033CL) +# define SEC_E_NO_PA_DATA ((HRESULT)0x8009033CL) #endif #ifndef SEC_E_PKINIT_NAME_MISMATCH -# define SEC_E_PKINIT_NAME_MISMATCH ((HRESULT)0x8009033DL) +# define SEC_E_PKINIT_NAME_MISMATCH ((HRESULT)0x8009033DL) #endif #ifndef SEC_E_SMARTCARD_LOGON_REQUIRED -# define SEC_E_SMARTCARD_LOGON_REQUIRED ((HRESULT)0x8009033EL) +# define SEC_E_SMARTCARD_LOGON_REQUIRED ((HRESULT)0x8009033EL) #endif #ifndef SEC_E_SHUTDOWN_IN_PROGRESS -# define SEC_E_SHUTDOWN_IN_PROGRESS ((HRESULT)0x8009033FL) +# define SEC_E_SHUTDOWN_IN_PROGRESS ((HRESULT)0x8009033FL) #endif #ifndef SEC_E_KDC_INVALID_REQUEST -# define SEC_E_KDC_INVALID_REQUEST ((HRESULT)0x80090340L) +# define SEC_E_KDC_INVALID_REQUEST ((HRESULT)0x80090340L) #endif #ifndef SEC_E_KDC_UNABLE_TO_REFER -# define SEC_E_KDC_UNABLE_TO_REFER ((HRESULT)0x80090341L) +# define SEC_E_KDC_UNABLE_TO_REFER ((HRESULT)0x80090341L) #endif #ifndef SEC_E_KDC_UNKNOWN_ETYPE -# define SEC_E_KDC_UNKNOWN_ETYPE ((HRESULT)0x80090342L) +# define SEC_E_KDC_UNKNOWN_ETYPE ((HRESULT)0x80090342L) #endif #ifndef SEC_E_UNSUPPORTED_PREAUTH -# define SEC_E_UNSUPPORTED_PREAUTH ((HRESULT)0x80090343L) +# define SEC_E_UNSUPPORTED_PREAUTH ((HRESULT)0x80090343L) #endif #ifndef SEC_E_DELEGATION_REQUIRED -# define SEC_E_DELEGATION_REQUIRED ((HRESULT)0x80090345L) +# define SEC_E_DELEGATION_REQUIRED ((HRESULT)0x80090345L) #endif #ifndef SEC_E_BAD_BINDINGS -# define SEC_E_BAD_BINDINGS ((HRESULT)0x80090346L) +# define SEC_E_BAD_BINDINGS ((HRESULT)0x80090346L) #endif #ifndef SEC_E_MULTIPLE_ACCOUNTS -# define SEC_E_MULTIPLE_ACCOUNTS ((HRESULT)0x80090347L) +# define SEC_E_MULTIPLE_ACCOUNTS ((HRESULT)0x80090347L) #endif #ifndef SEC_E_NO_KERB_KEY -# define SEC_E_NO_KERB_KEY ((HRESULT)0x80090348L) +# define SEC_E_NO_KERB_KEY ((HRESULT)0x80090348L) #endif #ifndef SEC_E_CERT_WRONG_USAGE -# define SEC_E_CERT_WRONG_USAGE ((HRESULT)0x80090349L) +# define SEC_E_CERT_WRONG_USAGE ((HRESULT)0x80090349L) #endif #ifndef SEC_E_DOWNGRADE_DETECTED -# define SEC_E_DOWNGRADE_DETECTED ((HRESULT)0x80090350L) +# define SEC_E_DOWNGRADE_DETECTED ((HRESULT)0x80090350L) #endif #ifndef SEC_E_SMARTCARD_CERT_REVOKED -# define SEC_E_SMARTCARD_CERT_REVOKED ((HRESULT)0x80090351L) +# define SEC_E_SMARTCARD_CERT_REVOKED ((HRESULT)0x80090351L) #endif #ifndef SEC_E_ISSUING_CA_UNTRUSTED -# define SEC_E_ISSUING_CA_UNTRUSTED ((HRESULT)0x80090352L) +# define SEC_E_ISSUING_CA_UNTRUSTED ((HRESULT)0x80090352L) #endif #ifndef SEC_E_REVOCATION_OFFLINE_C -# define SEC_E_REVOCATION_OFFLINE_C ((HRESULT)0x80090353L) +# define SEC_E_REVOCATION_OFFLINE_C ((HRESULT)0x80090353L) #endif #ifndef SEC_E_PKINIT_CLIENT_FAILURE -# define SEC_E_PKINIT_CLIENT_FAILURE ((HRESULT)0x80090354L) +# define SEC_E_PKINIT_CLIENT_FAILURE ((HRESULT)0x80090354L) #endif #ifndef SEC_E_SMARTCARD_CERT_EXPIRED -# define SEC_E_SMARTCARD_CERT_EXPIRED ((HRESULT)0x80090355L) +# define SEC_E_SMARTCARD_CERT_EXPIRED ((HRESULT)0x80090355L) #endif #ifndef SEC_E_NO_S4U_PROT_SUPPORT -# define SEC_E_NO_S4U_PROT_SUPPORT ((HRESULT)0x80090356L) +# define SEC_E_NO_S4U_PROT_SUPPORT ((HRESULT)0x80090356L) #endif #ifndef SEC_E_CROSSREALM_DELEGATION_FAILURE -# define SEC_E_CROSSREALM_DELEGATION_FAILURE ((HRESULT)0x80090357L) +# define SEC_E_CROSSREALM_DELEGATION_FAILURE ((HRESULT)0x80090357L) #endif #ifndef SEC_E_REVOCATION_OFFLINE_KDC -# define SEC_E_REVOCATION_OFFLINE_KDC ((HRESULT)0x80090358L) +# define SEC_E_REVOCATION_OFFLINE_KDC ((HRESULT)0x80090358L) #endif #ifndef SEC_E_ISSUING_CA_UNTRUSTED_KDC -# define SEC_E_ISSUING_CA_UNTRUSTED_KDC ((HRESULT)0x80090359L) +# define SEC_E_ISSUING_CA_UNTRUSTED_KDC ((HRESULT)0x80090359L) #endif #ifndef SEC_E_KDC_CERT_EXPIRED -# define SEC_E_KDC_CERT_EXPIRED ((HRESULT)0x8009035AL) +# define SEC_E_KDC_CERT_EXPIRED ((HRESULT)0x8009035AL) #endif #ifndef SEC_E_KDC_CERT_REVOKED -# define SEC_E_KDC_CERT_REVOKED ((HRESULT)0x8009035BL) +# define SEC_E_KDC_CERT_REVOKED ((HRESULT)0x8009035BL) #endif #ifndef SEC_E_INVALID_PARAMETER -# define SEC_E_INVALID_PARAMETER ((HRESULT)0x8009035DL) +# define SEC_E_INVALID_PARAMETER ((HRESULT)0x8009035DL) #endif #ifndef SEC_E_DELEGATION_POLICY -# define SEC_E_DELEGATION_POLICY ((HRESULT)0x8009035EL) +# define SEC_E_DELEGATION_POLICY ((HRESULT)0x8009035EL) #endif #ifndef SEC_E_POLICY_NLTM_ONLY -# define SEC_E_POLICY_NLTM_ONLY ((HRESULT)0x8009035FL) +# define SEC_E_POLICY_NLTM_ONLY ((HRESULT)0x8009035FL) #endif #ifndef SEC_I_CONTINUE_NEEDED -# define SEC_I_CONTINUE_NEEDED ((HRESULT)0x00090312L) +# define SEC_I_CONTINUE_NEEDED ((HRESULT)0x00090312L) #endif #ifndef SEC_I_COMPLETE_NEEDED -# define SEC_I_COMPLETE_NEEDED ((HRESULT)0x00090313L) +# define SEC_I_COMPLETE_NEEDED ((HRESULT)0x00090313L) #endif #ifndef SEC_I_COMPLETE_AND_CONTINUE -# define SEC_I_COMPLETE_AND_CONTINUE ((HRESULT)0x00090314L) +# define SEC_I_COMPLETE_AND_CONTINUE ((HRESULT)0x00090314L) #endif #ifndef SEC_I_LOCAL_LOGON -# define SEC_I_LOCAL_LOGON ((HRESULT)0x00090315L) +# define SEC_I_LOCAL_LOGON ((HRESULT)0x00090315L) #endif #ifndef SEC_I_CONTEXT_EXPIRED -# define SEC_I_CONTEXT_EXPIRED ((HRESULT)0x00090317L) +# define SEC_I_CONTEXT_EXPIRED ((HRESULT)0x00090317L) #endif #ifndef SEC_I_INCOMPLETE_CREDENTIALS -# define SEC_I_INCOMPLETE_CREDENTIALS ((HRESULT)0x00090320L) +# define SEC_I_INCOMPLETE_CREDENTIALS ((HRESULT)0x00090320L) #endif #ifndef SEC_I_RENEGOTIATE -# define SEC_I_RENEGOTIATE ((HRESULT)0x00090321L) +# define SEC_I_RENEGOTIATE ((HRESULT)0x00090321L) #endif #ifndef SEC_I_NO_LSA_CONTEXT -# define SEC_I_NO_LSA_CONTEXT ((HRESULT)0x00090323L) +# define SEC_I_NO_LSA_CONTEXT ((HRESULT)0x00090323L) #endif #ifndef SEC_I_SIGNATURE_NEEDED -# define SEC_I_SIGNATURE_NEEDED ((HRESULT)0x0009035CL) +# define SEC_I_SIGNATURE_NEEDED ((HRESULT)0x0009035CL) #endif #ifdef UNICODE diff --git a/Utilities/cmcurl/lib/curl_threads.c b/Utilities/cmcurl/lib/curl_threads.c index d40e024..f9b812e 100644 --- a/Utilities/cmcurl/lib/curl_threads.c +++ b/Utilities/cmcurl/lib/curl_threads.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -33,10 +33,6 @@ #endif #include "curl_threads.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" @@ -77,8 +73,8 @@ curl_thread_t Curl_thread_create(unsigned int (*func) (void*), void *arg) return t; err: - Curl_safefree(t); - Curl_safefree(ac); + free(t); + free(ac); return curl_thread_t_null; } @@ -123,7 +119,12 @@ void Curl_thread_destroy(curl_thread_t hnd) int Curl_thread_join(curl_thread_t *hnd) { +#if !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_VISTA) || \ + (_WIN32_WINNT < _WIN32_WINNT_VISTA) int ret = (WaitForSingleObject(*hnd, INFINITE) == WAIT_OBJECT_0); +#else + int ret = (WaitForSingleObjectEx(*hnd, INFINITE, FALSE) == WAIT_OBJECT_0); +#endif Curl_thread_destroy(*hnd); diff --git a/Utilities/cmcurl/lib/curl_threads.h b/Utilities/cmcurl/lib/curl_threads.h index 6457cbb..0f3191a 100644 --- a/Utilities/cmcurl/lib/curl_threads.h +++ b/Utilities/cmcurl/lib/curl_threads.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -37,7 +37,12 @@ # define curl_mutex_t CRITICAL_SECTION # define curl_thread_t HANDLE # define curl_thread_t_null (HANDLE)0 -# define Curl_mutex_init(m) InitializeCriticalSection(m) +# if !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_VISTA) || \ + (_WIN32_WINNT < _WIN32_WINNT_VISTA) +# define Curl_mutex_init(m) InitializeCriticalSection(m) +# else +# define Curl_mutex_init(m) InitializeCriticalSectionEx(m, 0, 1) +# endif # define Curl_mutex_acquire(m) EnterCriticalSection(m) # define Curl_mutex_release(m) LeaveCriticalSection(m) # define Curl_mutex_destroy(m) DeleteCriticalSection(m) diff --git a/Utilities/cmcurl/lib/curlx.h b/Utilities/cmcurl/lib/curlx.h index 9dc90a0..979e7d7 100644 --- a/Utilities/cmcurl/lib/curlx.h +++ b/Utilities/cmcurl/lib/curlx.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2008, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -90,8 +90,7 @@ #ifdef ENABLE_CURLX_PRINTF /* If this define is set, we define all "standard" printf() functions to use the curlx_* version instead. It makes the source code transparent and - easier to understand/patch. Undefine them first in case _MPRINTF_REPLACE - is set. */ + easier to understand/patch. Undefine them first. */ # undef printf # undef fprintf # undef sprintf diff --git a/Utilities/cmcurl/lib/dict.c b/Utilities/cmcurl/lib/dict.c index 86ddfb9..06d7699 100644 --- a/Utilities/cmcurl/lib/dict.c +++ b/Utilities/cmcurl/lib/dict.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -57,10 +57,6 @@ #include "strequal.h" #include "dict.h" #include "rawstr.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" @@ -101,7 +97,7 @@ static char *unescape_word(struct SessionHandle *data, const char *inputbuff) char *dictp; char *ptr; int len; - char byte; + char ch; int olen=0; newp = curl_easy_unescape(data, inputbuff, 0, &len); @@ -113,13 +109,13 @@ static char *unescape_word(struct SessionHandle *data, const char *inputbuff) /* According to RFC2229 section 2.2, these letters need to be escaped with \[letter] */ for(ptr = newp; - (byte = *ptr) != 0; + (ch = *ptr) != 0; ptr++) { - if((byte <= 32) || (byte == 127) || - (byte == '\'') || (byte == '\"') || (byte == '\\')) { + if((ch <= 32) || (ch == 127) || + (ch == '\'') || (ch == '\"') || (ch == '\\')) { dictp[olen++] = '\\'; } - dictp[olen++] = byte; + dictp[olen++] = ch; } dictp[olen]=0; } diff --git a/Utilities/cmcurl/lib/easy.c b/Utilities/cmcurl/lib/easy.c index 160712e..316acb1 100644 --- a/Utilities/cmcurl/lib/easy.c +++ b/Utilities/cmcurl/lib/easy.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -60,7 +60,6 @@ #include "hostip.h" #include "share.h" #include "strdup.h" -#include "curl_memory.h" #include "progress.h" #include "easyif.h" #include "select.h" @@ -74,11 +73,11 @@ #include "conncache.h" #include "multiif.h" #include "sigpipe.h" +#include "ssh.h" +#include "curl_printf.h" -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - -/* The last #include file should be: */ +/* The last #include files should be: */ +#include "curl_memory.h" #include "memdebug.h" /* win32_cleanup() is for win32 socket cleanup functionality, the opposite @@ -136,9 +135,9 @@ static CURLcode win32_init(void) #ifdef USE_WINDOWS_SSPI { - CURLcode err = Curl_sspi_global_init(); - if(err != CURLE_OK) - return err; + CURLcode result = Curl_sspi_global_init(); + if(result) + return result; } #endif @@ -243,7 +242,7 @@ CURLcode curl_global_init(long flags) } if(flags & CURL_GLOBAL_WIN32) - if(win32_init() != CURLE_OK) { + if(win32_init()) { DEBUGF(fprintf(stderr, "Error: win32_init failed\n")); return CURLE_FAILED_INIT; } @@ -265,7 +264,7 @@ CURLcode curl_global_init(long flags) idna_init(); #endif - if(Curl_resolver_global_init() != CURLE_OK) { + if(Curl_resolver_global_init()) { DEBUGF(fprintf(stderr, "Error: resolver_global_init failed\n")); return CURLE_FAILED_INIT; } @@ -293,7 +292,7 @@ CURLcode curl_global_init_mem(long flags, curl_malloc_callback m, curl_free_callback f, curl_realloc_callback r, curl_strdup_callback s, curl_calloc_callback c) { - CURLcode code = CURLE_OK; + CURLcode result = CURLE_OK; /* Invalid input, return immediately */ if(!m || !f || !r || !s || !c) @@ -308,8 +307,8 @@ CURLcode curl_global_init_mem(long flags, curl_malloc_callback m, } /* Call the actual init function first */ - code = curl_global_init(flags); - if(code == CURLE_OK) { + result = curl_global_init(flags); + if(!result) { Curl_cmalloc = m; Curl_cfree = f; Curl_cstrdup = s; @@ -317,7 +316,7 @@ CURLcode curl_global_init_mem(long flags, curl_malloc_callback m, Curl_ccalloc = c; } - return code; + return result; } /** @@ -357,13 +356,13 @@ void curl_global_cleanup(void) */ CURL *curl_easy_init(void) { - CURLcode res; + CURLcode result; struct SessionHandle *data; /* Make sure we inited the global SSL stuff */ if(!initialized) { - res = curl_global_init(CURL_GLOBAL_DEFAULT); - if(res) { + result = curl_global_init(CURL_GLOBAL_DEFAULT); + if(result) { /* something in the global init failed, return nothing */ DEBUGF(fprintf(stderr, "Error: curl_global_init failed\n")); return NULL; @@ -371,8 +370,8 @@ CURL *curl_easy_init(void) } /* We use curl_open() with undefined URL so far */ - res = Curl_open(&data); - if(res != CURLE_OK) { + result = Curl_open(&data); + if(result) { DEBUGF(fprintf(stderr, "Error: Curl_open failed\n")); return NULL; } @@ -390,17 +389,17 @@ CURLcode curl_easy_setopt(CURL *curl, CURLoption tag, ...) { va_list arg; struct SessionHandle *data = curl; - CURLcode ret; + CURLcode result; if(!curl) return CURLE_BAD_FUNCTION_ARGUMENT; va_start(arg, tag); - ret = Curl_setopt(data, tag, arg); + result = Curl_setopt(data, tag, arg); va_end(arg); - return ret; + return result; } #ifdef CURLDEBUG @@ -490,6 +489,10 @@ static int events_socket(CURL *easy, /* easy handle */ struct events *ev = userp; struct socketmonitor *m; struct socketmonitor *prev=NULL; + +#if defined(CURL_DISABLE_VERBOSE_STRINGS) + (void) easy; +#endif (void)socketp; m = ev->list; @@ -570,7 +573,7 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev) { bool done = FALSE; CURLMcode mcode; - CURLcode rc = CURLE_OK; + CURLcode result = CURLE_OK; while(!done) { CURLMsg *msg; @@ -630,6 +633,9 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev) ev->ms += curlx_tvdiff(after, before); } + else + return CURLE_RECV_ERROR; + if(mcode) return CURLE_URL_MALFORMAT; /* TODO: return a proper error! */ @@ -637,12 +643,12 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev) second argument */ msg = curl_multi_info_read(multi, &pollrc); if(msg) { - rc = msg->data.result; + result = msg->data.result; done = TRUE; } } - return rc; + return result; } @@ -668,7 +674,7 @@ static CURLcode easy_transfer(CURLM *multi) { bool done = FALSE; CURLMcode mcode = CURLM_OK; - CURLcode code = CURLE_OK; + CURLcode result = CURLE_OK; struct timeval before; int without_fds = 0; /* count number of consecutive returns from curl_multi_wait() without any filedescriptors */ @@ -683,7 +689,7 @@ static CURLcode easy_transfer(CURLM *multi) if(mcode == CURLM_OK) { if(ret == -1) { /* poll() failed not on EINTR, indicate a network problem */ - code = CURLE_RECV_ERROR; + result = CURLE_RECV_ERROR; break; } else if(ret == 0) { @@ -714,7 +720,7 @@ static CURLcode easy_transfer(CURLM *multi) int rc; CURLMsg *msg = curl_multi_info_read(multi, &rc); if(msg) { - code = msg->data.result; + result = msg->data.result; done = TRUE; } } @@ -728,7 +734,7 @@ static CURLcode easy_transfer(CURLM *multi) CURLE_BAD_FUNCTION_ARGUMENT; } - return code; + return result; } @@ -753,7 +759,7 @@ static CURLcode easy_perform(struct SessionHandle *data, bool events) { CURLM *multi; CURLMcode mcode; - CURLcode code = CURLE_OK; + CURLcode result = CURLE_OK; SIGPIPE_VARIABLE(pipe_st); if(!data) @@ -794,7 +800,7 @@ static CURLcode easy_perform(struct SessionHandle *data, bool events) data->multi = multi; /* run the transfer */ - code = events ? easy_events(multi) : easy_transfer(multi); + result = events ? easy_events(multi) : easy_transfer(multi); /* ignoring the return code isn't nice, but atm we can't really handle a failure here, room for future improvement! */ @@ -803,7 +809,7 @@ static CURLcode easy_perform(struct SessionHandle *data, bool events) sigpipe_restore(&pipe_st); /* The multi handle is kept alive, owned by the easy handle */ - return code; + return result; } @@ -854,16 +860,16 @@ CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...) { va_list arg; void *paramp; - CURLcode ret; + CURLcode result; struct SessionHandle *data = (struct SessionHandle *)curl; va_start(arg, info); paramp = va_arg(arg, void *); - ret = Curl_getinfo(data, info, paramp); + result = Curl_getinfo(data, info, paramp); va_end(arg); - return ret; + return result; } /* @@ -890,7 +896,7 @@ CURL *curl_easy_duphandle(CURL *incurl) outcurl->state.headersize = HEADERSIZE; /* copy all userdefined values */ - if(Curl_dupset(outcurl, data) != CURLE_OK) + if(Curl_dupset(outcurl, data)) goto fail; /* the connection cache is setup on demand */ @@ -936,7 +942,7 @@ CURL *curl_easy_duphandle(CURL *incurl) /* Clone the resolver handle, if present, for the new handle */ if(Curl_resolver_duphandle(&outcurl->state.resolver, - data->state.resolver) != CURLE_OK) + data->state.resolver)) goto fail; Curl_convert_setup(outcurl); @@ -1018,73 +1024,15 @@ CURLcode curl_easy_pause(CURL *curl, int action) /* we have a buffer for sending that we now seem to be able to deliver since the receive pausing is lifted! */ - /* get the pointer, type and length in local copies since the function may - return PAUSE again and then we'll get a new copy allocted and stored in + /* get the pointer in local copy since the function may return PAUSE + again and then we'll get a new copy allocted and stored in the tempwrite variables */ char *tempwrite = data->state.tempwrite; - char *freewrite = tempwrite; /* store this pointer to free it later */ - size_t tempsize = data->state.tempwritesize; - int temptype = data->state.tempwritetype; - size_t chunklen; - - /* clear tempwrite here just to make sure it gets cleared if there's no - further use of it, and make sure we don't clear it after the function - invoke as it may have been set to a new value by then */ - data->state.tempwrite = NULL; - - /* since the write callback API is define to never exceed - CURL_MAX_WRITE_SIZE bytes in a single call, and since we may in fact - have more data than that in our buffer here, we must loop sending the - data in multiple calls until there's no data left or we get another - pause returned. - - A tricky part is that the function we call will "buffer" the data - itself when it pauses on a particular buffer, so we may need to do some - extra trickery if we get a pause return here. - */ - do { - chunklen = (tempsize > CURL_MAX_WRITE_SIZE)?CURL_MAX_WRITE_SIZE:tempsize; - - result = Curl_client_write(data->easy_conn, - temptype, tempwrite, chunklen); - if(result) - /* failures abort the loop at once */ - break; - - if(data->state.tempwrite && (tempsize - chunklen)) { - /* Ouch, the reading is again paused and the block we send is now - "cached". If this is the final chunk we can leave it like this, but - if we have more chunks that are cached after this, we need to free - the newly cached one and put back a version that is truly the entire - contents that is saved for later - */ - char *newptr; - - /* note that tempsize is still the size as before the callback was - used, and thus the whole piece of data to keep */ - newptr = realloc(data->state.tempwrite, tempsize); - - if(!newptr) { - free(data->state.tempwrite); /* free old area */ - data->state.tempwrite = NULL; - result = CURLE_OUT_OF_MEMORY; - /* tempwrite will be freed further down */ - break; - } - data->state.tempwrite = newptr; /* store new pointer */ - memcpy(newptr, tempwrite, tempsize); - data->state.tempwritesize = tempsize; /* store new size */ - /* tempwrite will be freed further down */ - break; /* go back to pausing until further notice */ - } - else { - tempsize -= chunklen; /* left after the call above */ - tempwrite += chunklen; /* advance the pointer */ - } - } while((result == CURLE_OK) && tempsize); - - free(freewrite); /* this is unconditionally no longer used */ + data->state.tempwrite = NULL; + result = Curl_client_chop_write(data->easy_conn, data->state.tempwritetype, + tempwrite, data->state.tempwritesize); + free(tempwrite); } /* if there's no error and we're not pausing both directions, we want @@ -1129,20 +1077,20 @@ static CURLcode easy_connection(struct SessionHandle *data, CURLcode curl_easy_recv(CURL *curl, void *buffer, size_t buflen, size_t *n) { curl_socket_t sfd; - CURLcode ret; + CURLcode result; ssize_t n1; struct connectdata *c; struct SessionHandle *data = (struct SessionHandle *)curl; - ret = easy_connection(data, &sfd, &c); - if(ret) - return ret; + result = easy_connection(data, &sfd, &c); + if(result) + return result; *n = 0; - ret = Curl_read(c, sfd, buffer, buflen, &n1); + result = Curl_read(c, sfd, buffer, buflen, &n1); - if(ret != CURLE_OK) - return ret; + if(result) + return result; *n = (size_t)n1; @@ -1157,26 +1105,26 @@ CURLcode curl_easy_send(CURL *curl, const void *buffer, size_t buflen, size_t *n) { curl_socket_t sfd; - CURLcode ret; + CURLcode result; ssize_t n1; struct connectdata *c = NULL; struct SessionHandle *data = (struct SessionHandle *)curl; - ret = easy_connection(data, &sfd, &c); - if(ret) - return ret; + result = easy_connection(data, &sfd, &c); + if(result) + return result; *n = 0; - ret = Curl_write(c, sfd, buffer, buflen, &n1); + result = Curl_write(c, sfd, buffer, buflen, &n1); if(n1 == -1) return CURLE_SEND_ERROR; /* detect EAGAIN */ - if((CURLE_OK == ret) && (0 == n1)) + if(!result && !n1) return CURLE_AGAIN; *n = (size_t)n1; - return ret; + return result; } diff --git a/Utilities/cmcurl/lib/escape.c b/Utilities/cmcurl/lib/escape.c index d7f8a8f..24abb93 100644 --- a/Utilities/cmcurl/lib/escape.c +++ b/Utilities/cmcurl/lib/escape.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -27,16 +27,14 @@ #include <curl/curl.h> -#include "curl_memory.h" #include "urldata.h" #include "warnless.h" #include "non-ascii.h" #include "escape.h" +#include "curl_printf.h" -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - -/* The last #include file should be: */ +/* The last #include files should be: */ +#include "curl_memory.h" #include "memdebug.h" /* Portable character check (remember EBCDIC). Do not use isalnum() because @@ -87,7 +85,7 @@ char *curl_easy_escape(CURL *handle, const char *string, int inlength) size_t newlen = alloc; size_t strindex=0; size_t length; - CURLcode res; + CURLcode result; ns = malloc(alloc); if(!ns) @@ -115,8 +113,8 @@ char *curl_easy_escape(CURL *handle, const char *string, int inlength) } } - res = Curl_convert_to_network(handle, &in, 1); - if(res) { + result = Curl_convert_to_network(handle, &in, 1); + if(result) { /* Curl_convert_to_network calls failf if unsuccessful */ free(ns); return NULL; @@ -152,7 +150,7 @@ CURLcode Curl_urldecode(struct SessionHandle *data, unsigned char in; size_t strindex=0; unsigned long hex; - CURLcode res; + CURLcode result; if(!ns) return CURLE_OUT_OF_MEMORY; @@ -172,16 +170,17 @@ CURLcode Curl_urldecode(struct SessionHandle *data, in = curlx_ultouc(hex); /* this long is never bigger than 255 anyway */ - res = Curl_convert_from_network(data, &in, 1); - if(res) { + result = Curl_convert_from_network(data, &in, 1); + if(result) { /* Curl_convert_from_network calls failf if unsuccessful */ free(ns); - return res; + return result; } string+=2; alloc-=2; } + if(reject_ctrl && (in < 0x20)) { free(ns); return CURLE_URL_MALFORMAT; @@ -228,6 +227,5 @@ char *curl_easy_unescape(CURL *handle, const char *string, int length, the library's memory system */ void curl_free(void *p) { - if(p) - free(p); + free(p); } diff --git a/Utilities/cmcurl/lib/file.c b/Utilities/cmcurl/lib/file.c index 73df42e..175b107 100644 --- a/Utilities/cmcurl/lib/file.c +++ b/Utilities/cmcurl/lib/file.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -59,14 +59,12 @@ #include "getinfo.h" #include "transfer.h" #include "url.h" -#include "curl_memory.h" #include "parsedate.h" /* for the week day and month names */ #include "warnless.h" +#include "curl_printf.h" -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - -/* The last #include file should be: */ +/* The last #include files should be: */ +#include "curl_memory.h" #include "memdebug.h" #if defined(WIN32) || defined(MSDOS) || defined(__EMX__) || \ @@ -196,8 +194,9 @@ static CURLcode file_connect(struct connectdata *conn, bool *done) int i; char *actual_path; #endif + int real_path_len; - real_path = curl_easy_unescape(data, data->state.path, 0, NULL); + real_path = curl_easy_unescape(data, data->state.path, 0, &real_path_len); if(!real_path) return CURLE_OUT_OF_MEMORY; @@ -222,16 +221,23 @@ static CURLcode file_connect(struct connectdata *conn, bool *done) (actual_path[2] == ':' || actual_path[2] == '|')) { actual_path[2] = ':'; actual_path++; + real_path_len--; } /* change path separators from '/' to '\\' for DOS, Windows and OS/2 */ - for(i=0; actual_path[i] != '\0'; ++i) + for(i=0; i < real_path_len; ++i) if(actual_path[i] == '/') actual_path[i] = '\\'; + else if(!actual_path[i]) /* binary zero */ + return CURLE_URL_MALFORMAT; fd = open_readonly(actual_path, O_RDONLY|O_BINARY); file->path = actual_path; #else + if(memchr(real_path, 0, real_path_len)) + /* binary zeroes indicate foul play */ + return CURLE_URL_MALFORMAT; + fd = open_readonly(real_path, O_RDONLY); file->path = real_path; #endif @@ -295,7 +301,7 @@ static CURLcode file_upload(struct connectdata *conn) const char *dir = strchr(file->path, DIRSEP); int fd; int mode; - CURLcode res=CURLE_OK; + CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; char *buf = data->state.buffer; size_t nread; @@ -309,8 +315,6 @@ static CURLcode file_upload(struct connectdata *conn) * Since FILE: doesn't do the full init, we need to provide some extra * assignments here. */ - conn->fread_func = data->set.fread_func; - conn->fread_in = data->set.in; conn->data->req.upload_fromhere = buf; if(!dir) @@ -351,10 +355,10 @@ static CURLcode file_upload(struct connectdata *conn) data->state.resume_from = (curl_off_t)file_stat.st_size; } - while(res == CURLE_OK) { + while(!result) { int readcount; - res = Curl_fillreadbuffer(conn, BUFSIZE, &readcount); - if(res) + result = Curl_fillreadbuffer(conn, BUFSIZE, &readcount); + if(result) break; if(readcount <= 0) /* fix questionable compare error. curlvms */ @@ -381,7 +385,7 @@ static CURLcode file_upload(struct connectdata *conn) /* write the data to the target */ nwrite = write(fd, buf2, nread); if(nwrite != nread) { - res = CURLE_SEND_ERROR; + result = CURLE_SEND_ERROR; break; } @@ -390,16 +394,16 @@ static CURLcode file_upload(struct connectdata *conn) Curl_pgrsSetUploadCounter(data, bytecount); if(Curl_pgrsUpdate(conn)) - res = CURLE_ABORTED_BY_CALLBACK; + result = CURLE_ABORTED_BY_CALLBACK; else - res = Curl_speedcheck(data, now); + result = Curl_speedcheck(data, now); } - if(!res && Curl_pgrsUpdate(conn)) - res = CURLE_ABORTED_BY_CALLBACK; + if(!result && Curl_pgrsUpdate(conn)) + result = CURLE_ABORTED_BY_CALLBACK; close(fd); - return res; + return result; } /* @@ -417,7 +421,7 @@ static CURLcode file_do(struct connectdata *conn, bool *done) are supported. This means that files on remotely mounted directories (via NFS, Samba, NT sharing) can be accessed through a file:// URL */ - CURLcode res = CURLE_OK; + CURLcode result = CURLE_OK; 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' */ @@ -464,7 +468,6 @@ static CURLcode file_do(struct connectdata *conn, bool *done) information. Which for FILE can't be much more than the file size and date. */ if(data->set.opt_no_body && data->set.include_header && fstated) { - CURLcode result; snprintf(buf, sizeof(data->state.buffer), "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", expected_size); result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0); @@ -546,7 +549,7 @@ static CURLcode file_do(struct connectdata *conn, bool *done) Curl_pgrsTime(data, TIMER_STARTTRANSFER); - while(res == CURLE_OK) { + while(!result) { /* Don't fill a whole buffer if we want less than all data */ size_t bytestoread = (expected_size < CURL_OFF_T_C(BUFSIZE) - CURL_OFF_T_C(1)) ? @@ -563,21 +566,21 @@ static CURLcode file_do(struct connectdata *conn, bool *done) bytecount += nread; expected_size -= nread; - res = Curl_client_write(conn, CLIENTWRITE_BODY, buf, nread); - if(res) - return res; + result = Curl_client_write(conn, CLIENTWRITE_BODY, buf, nread); + if(result) + return result; Curl_pgrsSetDownloadCounter(data, bytecount); if(Curl_pgrsUpdate(conn)) - res = CURLE_ABORTED_BY_CALLBACK; + result = CURLE_ABORTED_BY_CALLBACK; else - res = Curl_speedcheck(data, now); + result = Curl_speedcheck(data, now); } if(Curl_pgrsUpdate(conn)) - res = CURLE_ABORTED_BY_CALLBACK; + result = CURLE_ABORTED_BY_CALLBACK; - return res; + return result; } #endif diff --git a/Utilities/cmcurl/lib/fileinfo.c b/Utilities/cmcurl/lib/fileinfo.c index 8c8ee98..0904937 100644 --- a/Utilities/cmcurl/lib/fileinfo.c +++ b/Utilities/cmcurl/lib/fileinfo.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2010-2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2010 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -24,10 +24,6 @@ #include "strdup.h" #include "fileinfo.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" diff --git a/Utilities/cmcurl/lib/formdata.c b/Utilities/cmcurl/lib/formdata.c index 3260928..9e8ce4e 100644 --- a/Utilities/cmcurl/lib/formdata.c +++ b/Utilities/cmcurl/lib/formdata.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -24,7 +24,7 @@ #include <curl/curl.h> -#if !defined(CURL_DISABLE_HTTP) || defined(USE_SSLEAY) +#ifndef CURL_DISABLE_HTTP #if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME) #include <libgen.h> @@ -34,19 +34,14 @@ #include "formdata.h" #include "vtls/vtls.h" #include "strequal.h" -#include "curl_memory.h" #include "sendf.h" +#include "strdup.h" +#include "curl_printf.h" -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - -/* The last #include file should be: */ +/* The last #include files should be: */ +#include "curl_memory.h" #include "memdebug.h" -#endif /* !defined(CURL_DISABLE_HTTP) || defined(USE_SSLEAY) */ - -#ifndef CURL_DISABLE_HTTP - #ifndef HAVE_BASENAME static char *Curl_basename(char *path); #define basename(x) Curl_basename((x)) @@ -214,46 +209,6 @@ static const char *ContentTypeForFilename(const char *filename, /*************************************************************************** * - * memdup() - * - * Copies the 'source' data to a newly allocated buffer buffer (that is - * returned). Uses buffer_length if not null, else uses strlen to determine - * the length of the buffer to be copied - * - * Returns the new pointer or NULL on failure. - * - ***************************************************************************/ -static char *memdup(const char *src, size_t buffer_length) -{ - size_t length; - bool add = FALSE; - char *buffer; - - if(buffer_length) - length = buffer_length; - else if(src) { - length = strlen(src); - add = TRUE; - } - else - /* no length and a NULL src pointer! */ - return strdup(""); - - buffer = malloc(length+add); - if(!buffer) - return NULL; /* fail */ - - memcpy(buffer, src, length); - - /* if length unknown do null termination */ - if(add) - buffer[length] = '\0'; - - return buffer; -} - -/*************************************************************************** - * * FormAdd() * * Stores a formpost parameter and builds the appropriate linked list. @@ -460,7 +415,7 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost, else { form = AddFormInfo(fname, NULL, current_form); if(!form) { - Curl_safefree(fname); + free(fname); return_value = CURL_FORMADD_MEMORY; } else { @@ -549,7 +504,7 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost, else { form = AddFormInfo(NULL, type, current_form); if(!form) { - Curl_safefree(type); + free(type); return_value = CURL_FORMADD_MEMORY; } else { @@ -682,9 +637,12 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost, (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) + if(form->name) { /* copy name (without strdup; possibly contains null characters) */ - form->name = memdup(form->name, form->namelength); + form->name = Curl_memdup(form->name, form->namelength? + form->namelength: + strlen(form->name)+1); + } if(!form->name) { return_value = CURL_FORMADD_MEMORY; break; @@ -693,9 +651,11 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost, } if(!(form->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE | HTTPPOST_PTRCONTENTS | HTTPPOST_PTRBUFFER | - HTTPPOST_CALLBACK)) ) { + HTTPPOST_CALLBACK)) && form->value) { /* copy value (without strdup; possibly contains null characters) */ - form->value = memdup(form->value, form->contentslength); + form->value = Curl_memdup(form->value, form->contentslength? + form->contentslength: + strlen(form->value)+1); if(!form->value) { return_value = CURL_FORMADD_MEMORY; break; @@ -751,7 +711,7 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost, now by the httppost linked list */ while(first_form) { FormInfo *ptr = first_form->more; - Curl_safefree(first_form); + free(first_form); first_form = ptr; } @@ -796,7 +756,7 @@ curl_off_t VmsRealFileSize(const char * name, int ret_stat; FILE * file; - file = fopen(name, "r"); + file = fopen(name, "r"); /* VMS */ if(file == NULL) return 0; @@ -954,13 +914,13 @@ void Curl_formclean(struct FormData **form_ptr) int curl_formget(struct curl_httppost *form, void *arg, curl_formget_callback append) { - CURLcode rc; + CURLcode result; curl_off_t size; struct FormData *data, *ptr; - rc = Curl_getformdata(NULL, &data, form, NULL, &size); - if(rc != CURLE_OK) - return (int)rc; + 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)) { @@ -1009,19 +969,16 @@ void curl_formfree(struct curl_httppost *form) next=form->next; /* the following form line */ /* recurse to sub-contents */ - if(form->more) - curl_formfree(form->more); + curl_formfree(form->more); - if(!(form->flags & HTTPPOST_PTRNAME) && form->name) + if(!(form->flags & HTTPPOST_PTRNAME)) free(form->name); /* free the name */ if(!(form->flags & - (HTTPPOST_PTRCONTENTS|HTTPPOST_BUFFER|HTTPPOST_CALLBACK)) && - form->contents) + (HTTPPOST_PTRCONTENTS|HTTPPOST_BUFFER|HTTPPOST_CALLBACK)) + ) free(form->contents); /* free the contents */ - if(form->contenttype) - free(form->contenttype); /* free the content type */ - if(form->showfilename) - free(form->showfilename); /* free the faked file name */ + free(form->contenttype); /* free the content type */ + free(form->showfilename); /* free the faked file name */ free(form); /* free the struct */ } while((form = next) != NULL); /* continue */ @@ -1111,7 +1068,7 @@ static CURLcode formdata_add_filename(const struct curl_httppost *file, /* filename need be escaped */ filename_escaped = malloc(strlen(filename)*2+1); if(!filename_escaped) { - Curl_safefree(filebasename); + free(filebasename); return CURLE_OUT_OF_MEMORY; } p0 = filename_escaped; @@ -1127,8 +1084,8 @@ static CURLcode formdata_add_filename(const struct curl_httppost *file, result = AddFormDataf(form, size, "; filename=\"%s\"", filename); - Curl_safefree(filename_escaped); - Curl_safefree(filebasename); + free(filename_escaped); + free(filebasename); return result; } @@ -1178,7 +1135,7 @@ CURLcode Curl_getformdata(struct SessionHandle *data, boundary); if(result) { - Curl_safefree(boundary); + free(boundary); return result; } /* we DO NOT include that line in the total size of the POST, since it'll be @@ -1221,7 +1178,7 @@ CURLcode Curl_getformdata(struct SessionHandle *data, /* 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 */ - Curl_safefree(fileboundary); + free(fileboundary); fileboundary = formboundary(data); if(!fileboundary) { result = CURLE_OUT_OF_MEMORY; @@ -1369,22 +1326,20 @@ CURLcode Curl_getformdata(struct SessionHandle *data, } while((post = post->next) != NULL); /* for each field */ /* end-boundary for everything */ - if(CURLE_OK == result) - result = AddFormDataf(&form, &size, - "\r\n--%s--\r\n", - boundary); + if(!result) + result = AddFormDataf(&form, &size, "\r\n--%s--\r\n", boundary); if(result) { Curl_formclean(&firstform); - Curl_safefree(fileboundary); - Curl_safefree(boundary); + free(fileboundary); + free(boundary); return result; } *sizep = size; - Curl_safefree(fileboundary); - Curl_safefree(boundary); + free(fileboundary); + free(boundary); *finalform = firstform; @@ -1430,7 +1385,7 @@ static FILE * vmsfopenread(const char *file, const char *mode) { case FAB$C_VAR: case FAB$C_VFC: case FAB$C_STMCR: - return fopen(file, "r"); + return fopen(file, "r"); /* VMS */ break; default: return fopen(file, "r", "rfm=stmlf", "ctx=stm"); diff --git a/Utilities/cmcurl/lib/ftp.c b/Utilities/cmcurl/lib/ftp.c index 1644983..74c4032 100644 --- a/Utilities/cmcurl/lib/ftp.c +++ b/Utilities/cmcurl/lib/ftp.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -77,9 +77,7 @@ #include "warnless.h" #include "http_proxy.h" #include "non-ascii.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> +#include "curl_printf.h" #include "curl_memory.h" /* The last #include file should be: */ @@ -157,7 +155,7 @@ static CURLcode ftp_dophase_done(struct connectdata *conn, bool connected); /* easy-to-use macro: */ -#define PPSENDF(x,y,z) if((result = Curl_pp_sendf(x,y,z)) != CURLE_OK) \ +#define PPSENDF(x,y,z) if((result = Curl_pp_sendf(x,y,z))) \ return result @@ -285,19 +283,17 @@ static void freedirs(struct ftp_conn *ftpc) int i; if(ftpc->dirs) { for(i=0; i < ftpc->dirdepth; i++) { - if(ftpc->dirs[i]) { - free(ftpc->dirs[i]); - ftpc->dirs[i]=NULL; - } + free(ftpc->dirs[i]); + ftpc->dirs[i]=NULL; } free(ftpc->dirs); ftpc->dirs = NULL; ftpc->dirdepth = 0; } - if(ftpc->file) { - free(ftpc->file); - ftpc->file = NULL; - } + Curl_safefree(ftpc->file); + + /* no longer of any use */ + Curl_safefree(ftpc->newhost); } /* Returns non-zero if the given string contains CR (\r) or LF (\n), @@ -346,7 +342,7 @@ static CURLcode AcceptServerConnect(struct connectdata *conn) infof(data, "Connection accepted from server\n"); conn->sock[SECONDARYSOCKET] = s; - curlx_nonblock(s, TRUE); /* enable non-blocking */ + (void)curlx_nonblock(s, TRUE); /* enable non-blocking */ conn->sock_accepted[SECONDARYSOCKET] = TRUE; if(data->set.fsockopt) { @@ -541,7 +537,7 @@ static CURLcode AllowServerConnect(struct connectdata *conn, bool *connected) { struct SessionHandle *data = conn->data; long timeout_ms; - CURLcode ret = CURLE_OK; + CURLcode result = CURLE_OK; *connected = FALSE; infof(data, "Preparing for accepting server on data port\n"); @@ -557,22 +553,22 @@ static CURLcode AllowServerConnect(struct connectdata *conn, bool *connected) } /* see if the connection request is already here */ - ret = ReceivedServerConnect(conn, connected); - if(ret) - return ret; + result = ReceivedServerConnect(conn, connected); + if(result) + return result; if(*connected) { - ret = AcceptServerConnect(conn); - if(ret) - return ret; + result = AcceptServerConnect(conn); + if(result) + return result; - ret = InitiateTransfer(conn); - if(ret) - return ret; + result = InitiateTransfer(conn); + if(result) + return result; } else { /* Add timeout to multi handle and break out of the loop */ - if(ret == CURLE_OK && *connected == FALSE) { + if(!result && *connected == FALSE) { if(data->set.accepttimeout > 0) Curl_expire(data, data->set.accepttimeout); else @@ -580,7 +576,7 @@ static CURLcode AllowServerConnect(struct connectdata *conn, bool *connected) } } - return ret; + return result; } /* macro to check for a three-digit ftp status code at the start of the @@ -821,12 +817,19 @@ static void _state(struct connectdata *conn, ) { struct ftp_conn *ftpc = &conn->proto.ftpc; -#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) + +#if defined(DEBUGBUILD) + +#if defined(CURL_DISABLE_VERBOSE_STRINGS) + (void) lineno; +#else if(ftpc->state != newstate) infof(conn->data, "FTP %p (line %d) state change from %s to %s\n", (void *)ftpc, lineno, ftp_state_names[ftpc->state], ftp_state_names[newstate]); #endif +#endif + ftpc->state = newstate; } @@ -1072,8 +1075,9 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, if(*addr != '\0') { /* attempt to get the address of the given interface name */ - switch(Curl_if2ip(conn->ip_addr->ai_family, conn->scope, addr, - hbuf, sizeof(hbuf))) { + switch(Curl_if2ip(conn->ip_addr->ai_family, + Curl_ipv6_scope(conn->ip_addr->ai_addr), + conn->scope_id, addr, hbuf, sizeof(hbuf))) { case IF2IP_NOT_FOUND: /* not an interface, use the given string as host name instead */ host = addr; @@ -1097,7 +1101,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) { failf(data, "getsockname() failed: %s", Curl_strerror(conn, SOCKERRNO) ); - Curl_safefree(addr); + free(addr); return CURLE_FTP_PORT_FAILED; } switch(sa->sa_family) { @@ -1129,11 +1133,11 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, if(res == NULL) { failf(data, "failed to resolve the address provided to PORT: %s", host); - Curl_safefree(addr); + free(addr); return CURLE_FTP_PORT_FAILED; } - Curl_safefree(addr); + free(addr); host = NULL; /* step 2, create a socket for the requested address */ @@ -1246,10 +1250,10 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, continue; if((PORT == fcmd) && sa->sa_family != AF_INET) - /* PORT is ipv4 only */ + /* PORT is IPv4 only */ continue; - switch (sa->sa_family) { + switch(sa->sa_family) { case AF_INET: port = ntohs(sa4->sin_port); break; @@ -1487,13 +1491,13 @@ static CURLcode ftp_state_list(struct connectdata *conn) The other ftp_filemethods will CWD into dir/dir/ first and then just do LIST (in that case: nothing to do here) */ - char *cmd,*lstArg,*slashPos; + char *cmd, *lstArg, *slashPos; lstArg = NULL; if((data->set.ftp_filemethod == FTPFILE_NOCWD) && data->state.path && data->state.path[0] && - strchr(data->state.path,'/')) { + strchr(data->state.path, '/')) { lstArg = strdup(data->state.path); if(!lstArg) @@ -1503,7 +1507,7 @@ static CURLcode ftp_state_list(struct connectdata *conn) if(lstArg[strlen(lstArg) - 1] != '/') { /* chop off the file part if format is dir/dir/file */ - slashPos = strrchr(lstArg,'/'); + slashPos = strrchr(lstArg, '/'); if(slashPos) *(slashPos+1) = '\0'; } @@ -1517,19 +1521,16 @@ static CURLcode ftp_state_list(struct connectdata *conn) lstArg? lstArg: "" ); if(!cmd) { - if(lstArg) - free(lstArg); + free(lstArg); return CURLE_OUT_OF_MEMORY; } result = Curl_pp_sendf(&conn->proto.ftpc.pp, "%s", cmd); - if(lstArg) - free(lstArg); - + free(lstArg); free(cmd); - if(result != CURLE_OK) + if(result) return result; state(conn, FTP_LIST); @@ -1669,8 +1670,8 @@ static CURLcode ftp_state_ul_setup(struct connectdata *conn, BUFSIZE : curlx_sotouz(data->state.resume_from - passed); size_t actuallyread = - conn->fread_func(data->state.buffer, 1, readthisamountnow, - conn->fread_in); + data->set.fread_func(data->state.buffer, 1, readthisamountnow, + data->set.in); passed += actuallyread; if((actuallyread == 0) || (actuallyread > readthisamountnow)) { @@ -1807,6 +1808,13 @@ static CURLcode ftp_state_quote(struct connectdata *conn, static CURLcode ftp_epsv_disable(struct connectdata *conn) { CURLcode result = CURLE_OK; + + if(conn->bits.ipv6) { + /* We can't disable EPSV when doing IPv6, so this is instead a fail */ + failf(conn->data, "Failed EPSV attempt, exiting\n"); + return CURLE_FTP_WEIRD_SERVER_REPLY; + } + infof(conn->data, "Failed EPSV attempt. Disabling EPSV\n"); /* disable it for next transfer */ conn->bits.ftp_use_epsv = FALSE; @@ -1828,9 +1836,15 @@ static CURLcode proxy_magic(struct connectdata *conn, bool *magicdone) { CURLcode result = CURLE_OK; - struct SessionHandle *data=conn->data; + struct SessionHandle *data = conn->data; + +#if defined(CURL_DISABLE_PROXY) + (void) newhost; + (void) newport; +#endif *magicdone = FALSE; + switch(conn->proxytype) { case CURLPROXY_SOCKS5: case CURLPROXY_SOCKS5_HOSTNAME: @@ -1873,7 +1887,7 @@ static CURLcode proxy_magic(struct connectdata *conn, memset(&http_proxy, 0, sizeof(http_proxy)); data->req.protop = &http_proxy; - result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, newhost, newport); + result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, newhost, newport, TRUE); data->req.protop = ftp_save; @@ -1888,9 +1902,26 @@ static CURLcode proxy_magic(struct connectdata *conn, else *magicdone = TRUE; } + return result; } +static char *control_address(struct connectdata *conn) +{ + /* Returns the control connection IP address. + If a proxy tunnel is used, returns the original host name instead, because + the effective control connection address is the proxy address, + not the ftp host. */ + if(conn->bits.tunnel_proxy || + conn->proxytype == CURLPROXY_SOCKS5 || + conn->proxytype == CURLPROXY_SOCKS5_HOSTNAME || + conn->proxytype == CURLPROXY_SOCKS4 || + conn->proxytype == CURLPROXY_SOCKS4A) + return conn->host.name; + + return conn->ip_addr_str; +} + static CURLcode ftp_state_pasv_resp(struct connectdata *conn, int ftpcode) { @@ -1902,6 +1933,9 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn, unsigned short connectport; /* the local port connect() should use! */ 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); + if((ftpc->count1 == 0) && (ftpcode == 229)) { /* positive EPSV response */ @@ -1910,12 +1944,12 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn, unsigned int num; char separator[4]; ptr++; - if(5 == sscanf(ptr, "%c%c%c%u%c", - &separator[0], - &separator[1], - &separator[2], - &num, - &separator[3])) { + if(5 == sscanf(ptr, "%c%c%c%u%c", + &separator[0], + &separator[1], + &separator[2], + &num, + &separator[3])) { const char sep1 = separator[0]; int i; @@ -1933,19 +1967,9 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn, } if(ptr) { ftpc->newport = (unsigned short)(num & 0xffff); - - if(conn->bits.tunnel_proxy || - conn->proxytype == CURLPROXY_SOCKS5 || - conn->proxytype == CURLPROXY_SOCKS5_HOSTNAME || - conn->proxytype == CURLPROXY_SOCKS4 || - conn->proxytype == CURLPROXY_SOCKS4A) - /* proxy tunnel -> use other host info because ip_addr_str is the - proxy address not the ftp host */ - snprintf(ftpc->newhost, sizeof(ftpc->newhost), "%s", - conn->host.name); - else - /* use the same IP we are already connected to */ - snprintf(ftpc->newhost, NEWHOST_BUFSIZE, "%s", conn->ip_addr_str); + ftpc->newhost = strdup(control_address(conn)); + if(!ftpc->newhost) + return CURLE_OUT_OF_MEMORY; } } else @@ -1973,8 +1997,8 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn, */ while(*str) { if(6 == sscanf(str, "%d,%d,%d,%d,%d,%d", - &ip[0], &ip[1], &ip[2], &ip[3], - &port[0], &port[1])) + &ip[0], &ip[1], &ip[2], &ip[3], + &port[0], &port[1])) break; str++; } @@ -1986,26 +2010,19 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn, /* we got OK from server */ if(data->set.ftp_skip_ip) { - /* told to ignore the remotely given IP but instead use the one we used + /* told to ignore the remotely given IP but instead use the host we used for the control connection */ - infof(data, "Skips %d.%d.%d.%d for data connection, uses %s instead\n", + infof(data, "Skip %d.%d.%d.%d for data connection, re-use %s instead\n", ip[0], ip[1], ip[2], ip[3], - conn->ip_addr_str); - if(conn->bits.tunnel_proxy || - conn->proxytype == CURLPROXY_SOCKS5 || - conn->proxytype == CURLPROXY_SOCKS5_HOSTNAME || - conn->proxytype == CURLPROXY_SOCKS4 || - conn->proxytype == CURLPROXY_SOCKS4A) - /* proxy tunnel -> use other host info because ip_addr_str is the - proxy address not the ftp host */ - snprintf(ftpc->newhost, sizeof(ftpc->newhost), "%s", conn->host.name); - else - snprintf(ftpc->newhost, sizeof(ftpc->newhost), "%s", - conn->ip_addr_str); + conn->host.name); + ftpc->newhost = strdup(control_address(conn)); } else - snprintf(ftpc->newhost, sizeof(ftpc->newhost), - "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); + ftpc->newhost = aprintf("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); + + if(!ftpc->newhost) + return CURLE_OUT_OF_MEMORY; + ftpc->newport = (unsigned short)(((port[0]<<8) + port[1]) & 0xffff); } else if(ftpc->count1 == 0) { @@ -2056,9 +2073,8 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn, conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE; result = Curl_connecthost(conn, addr); - Curl_resolv_unlock(data, addr); /* we're done using this address */ - if(result) { + Curl_resolv_unlock(data, addr); /* we're done using this address */ if(ftpc->count1 == 0 && ftpcode == 229) return ftp_epsv_disable(conn); @@ -2074,8 +2090,9 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn, if(data->set.verbose) /* this just dumps information about this second connection */ - ftp_pasv_verbose(conn, conn->ip_addr, ftpc->newhost, connectport); + ftp_pasv_verbose(conn, addr->addr, ftpc->newhost, connectport); + Curl_resolv_unlock(data, addr); /* we're done using this address */ conn->bits.do_more = TRUE; state(conn, FTP_STOP); /* this phase is completed */ @@ -2090,7 +2107,9 @@ static CURLcode ftp_state_port_resp(struct connectdata *conn, ftpport fcmd = (ftpport)ftpc->count1; CURLcode result = CURLE_OK; - if(ftpcode != 200) { + /* The FTP spec tells a positive response should have code 200. + Be more permissive here to tolerate deviant servers. */ + if(ftpcode / 100 != 2) { /* the command failed */ if(EPRT == fcmd) { @@ -2714,7 +2733,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) set a valid level */ Curl_sec_request_prot(conn, data->set.str[STRING_KRB_LEVEL]); - if(Curl_sec_login(conn) != CURLE_OK) + if(Curl_sec_login(conn)) infof(data, "Logging in with password in cleartext!\n"); else infof(data, "Authentication successful\n"); @@ -2765,7 +2784,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) if((ftpcode == 234) || (ftpcode == 334)) { /* Curl_ssl_connect is BLOCKING */ result = Curl_ssl_connect(conn, FIRSTSOCKET); - if(CURLE_OK == result) { + if(!result) { conn->ssl[SECONDARYSOCKET].use = FALSE; /* clear-text data */ result = ftp_state_user(conn); } @@ -2907,7 +2926,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) if(!ftpc->server_os && dir[0] != '/') { result = Curl_pp_sendf(&ftpc->pp, "%s", "SYST"); - if(result != CURLE_OK) { + if(result) { free(dir); return result; } @@ -2960,7 +2979,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) if(strequal(os, "OS/400")) { /* Force OS400 name format 1. */ result = Curl_pp_sendf(&ftpc->pp, "%s", "SITE NAMEFMT 1"); - if(result != CURLE_OK) { + if(result) { free(os); return result; } @@ -3254,8 +3273,7 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status, } /* now store a copy of the directory we are in */ - if(ftpc->prevpath) - free(ftpc->prevpath); + free(ftpc->prevpath); if(data->set.wildcardmatch) { if(data->set.chunk_end && ftpc->file) { @@ -3304,7 +3322,7 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status, /* shut down the socket to inform the server we're done */ #ifdef _WIN32_WCE - shutdown(conn->sock[SECONDARYSOCKET],2); /* SD_BOTH */ + shutdown(conn->sock[SECONDARYSOCKET], 2); /* SD_BOTH */ #endif if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) { @@ -3627,7 +3645,7 @@ static CURLcode ftp_do_more(struct connectdata *conn, int *completep) if(conn->tunnel_state[SECONDARYSOCKET] == TUNNEL_CONNECT) { /* 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); + result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, NULL, 0, FALSE); return result; } @@ -3736,7 +3754,7 @@ static CURLcode ftp_do_more(struct connectdata *conn, int *completep) return result; } - if((result == CURLE_OK) && (ftp->transfer != FTPTRANSFER_BODY)) + if(!result && (ftp->transfer != FTPTRANSFER_BODY)) /* no data to transfer. FIX: it feels like a kludge to have this here too! */ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); @@ -3802,7 +3820,7 @@ static void wc_data_dtor(void *ptr) struct ftp_wc_tmpdata *tmp = ptr; if(tmp) Curl_ftp_parselist_data_free(&tmp->parser); - Curl_safefree(tmp); + free(tmp); } static CURLcode init_wc_data(struct connectdata *conn) @@ -3810,7 +3828,7 @@ static CURLcode init_wc_data(struct connectdata *conn) char *last_slash; char *path = conn->data->state.path; struct WildcardData *wildcard = &(conn->data->wildcard); - CURLcode ret = CURLE_OK; + CURLcode result = CURLE_OK; struct ftp_wc_tmpdata *ftp_tmp; last_slash = strrchr(conn->data->state.path, '/'); @@ -3818,8 +3836,8 @@ static CURLcode init_wc_data(struct connectdata *conn) last_slash++; if(last_slash[0] == '\0') { wildcard->state = CURLWC_CLEAN; - ret = ftp_parse_url_path(conn); - return ret; + result = ftp_parse_url_path(conn); + return result; } else { wildcard->pattern = strdup(last_slash); @@ -3837,8 +3855,8 @@ static CURLcode init_wc_data(struct connectdata *conn) } else { /* only list */ wildcard->state = CURLWC_CLEAN; - ret = ftp_parse_url_path(conn); - return ret; + result = ftp_parse_url_path(conn); + return result; } } @@ -3856,7 +3874,7 @@ static CURLcode init_wc_data(struct connectdata *conn) ftp_tmp->parser = Curl_ftp_parselist_data_alloc(); if(!ftp_tmp->parser) { Curl_safefree(wildcard->pattern); - Curl_safefree(ftp_tmp); + free(ftp_tmp); return CURLE_OUT_OF_MEMORY; } @@ -3868,13 +3886,13 @@ static CURLcode init_wc_data(struct connectdata *conn) conn->data->set.ftp_filemethod = FTPFILE_MULTICWD; /* try to parse ftp url */ - ret = ftp_parse_url_path(conn); - if(ret) { + result = ftp_parse_url_path(conn); + if(result) { Curl_safefree(wildcard->pattern); wildcard->tmp_dtor(wildcard->tmp); wildcard->tmp_dtor = ZERO_NULL; wildcard->tmp = NULL; - return ret; + return result; } wildcard->path = strdup(conn->data->state.path); @@ -3903,16 +3921,16 @@ static CURLcode init_wc_data(struct connectdata *conn) static CURLcode wc_statemach(struct connectdata *conn) { struct WildcardData * const wildcard = &(conn->data->wildcard); - CURLcode ret = CURLE_OK; + CURLcode result = CURLE_OK; switch (wildcard->state) { case CURLWC_INIT: - ret = init_wc_data(conn); + result = init_wc_data(conn); if(wildcard->state == CURLWC_CLEAN) /* only listing! */ break; else - wildcard->state = ret ? CURLWC_ERROR : CURLWC_MATCHING; + wildcard->state = result ? CURLWC_ERROR : CURLWC_MATCHING; break; case CURLWC_MATCHING: { @@ -3976,10 +3994,9 @@ static CURLcode wc_statemach(struct connectdata *conn) if(finfo->flags & CURLFINFOFLAG_KNOWN_SIZE) ftpc->known_filesize = finfo->size; - ret = ftp_parse_url_path(conn); - if(ret) { - return ret; - } + result = ftp_parse_url_path(conn); + if(result) + return result; /* we don't need the Curl_fileinfo of first file anymore */ Curl_llist_remove(wildcard->filelist, wildcard->filelist->head, NULL); @@ -4003,11 +4020,11 @@ static CURLcode wc_statemach(struct connectdata *conn) case CURLWC_CLEAN: { struct ftp_wc_tmpdata *ftp_tmp = wildcard->tmp; - ret = CURLE_OK; - if(ftp_tmp) { - ret = Curl_ftp_parselist_geterror(ftp_tmp->parser); - } - wildcard->state = ret ? CURLWC_ERROR : CURLWC_DONE; + result = CURLE_OK; + if(ftp_tmp) + result = Curl_ftp_parselist_geterror(ftp_tmp->parser); + + wildcard->state = result ? CURLWC_ERROR : CURLWC_DONE; } break; case CURLWC_DONE: @@ -4015,7 +4032,7 @@ static CURLcode wc_statemach(struct connectdata *conn) break; } - return ret; + return result; } /*********************************************************************** @@ -4029,31 +4046,31 @@ static CURLcode wc_statemach(struct connectdata *conn) */ static CURLcode ftp_do(struct connectdata *conn, bool *done) { - CURLcode retcode = CURLE_OK; + CURLcode result = CURLE_OK; struct ftp_conn *ftpc = &conn->proto.ftpc; *done = FALSE; /* default to false */ ftpc->wait_data_conn = FALSE; /* default to no such wait */ if(conn->data->set.wildcardmatch) { - retcode = wc_statemach(conn); + result = wc_statemach(conn); if(conn->data->wildcard.state == CURLWC_SKIP || conn->data->wildcard.state == CURLWC_DONE) { /* do not call ftp_regular_transfer */ return CURLE_OK; } - if(retcode) /* error, loop or skipping the file */ - return retcode; + if(result) /* error, loop or skipping the file */ + return result; } else { /* no wildcard FSM needed */ - retcode = ftp_parse_url_path(conn); - if(retcode) - return retcode; + result = ftp_parse_url_path(conn); + if(result) + return result; } - retcode = ftp_regular_transfer(conn, done); + result = ftp_regular_transfer(conn, done); - return retcode; + return result; } @@ -4065,7 +4082,7 @@ CURLcode Curl_ftpsendf(struct connectdata *conn, char s[SBUF_SIZE]; size_t write_len; char *sptr=s; - CURLcode res = CURLE_OK; + CURLcode result = CURLE_OK; #ifdef HAVE_GSSAPI enum protection_level data_sec = conn->data_prot; #endif @@ -4080,23 +4097,23 @@ CURLcode Curl_ftpsendf(struct connectdata *conn, bytes_written=0; - res = Curl_convert_to_network(conn->data, s, write_len); + result = Curl_convert_to_network(conn->data, s, write_len); /* Curl_convert_to_network calls failf if unsuccessful */ - if(res) - return(res); + if(result) + return result; for(;;) { #ifdef HAVE_GSSAPI conn->data_prot = PROT_CMD; #endif - res = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len, - &bytes_written); + result = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len, + &bytes_written); #ifdef HAVE_GSSAPI DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST); conn->data_prot = data_sec; #endif - if(CURLE_OK != res) + if(result) break; if(conn->data->set.verbose) @@ -4111,7 +4128,7 @@ CURLcode Curl_ftpsendf(struct connectdata *conn, break; } - return res; + return result; } /*********************************************************************** @@ -4182,14 +4199,10 @@ static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection) } freedirs(ftpc); - if(ftpc->prevpath) { - free(ftpc->prevpath); - ftpc->prevpath = NULL; - } - if(ftpc->server_os) { - free(ftpc->server_os); - ftpc->server_os = NULL; - } + free(ftpc->prevpath); + ftpc->prevpath = NULL; + free(ftpc->server_os); + ftpc->server_os = NULL; Curl_pp_disconnect(pp); @@ -4480,7 +4493,7 @@ CURLcode ftp_regular_transfer(struct connectdata *conn, &connected, /* have we connected after PASV/PORT */ dophase_done); /* all commands in the DO-phase done? */ - if(CURLE_OK == result) { + if(!result) { if(!*dophase_done) /* the DO phase has not completed yet */ diff --git a/Utilities/cmcurl/lib/ftp.h b/Utilities/cmcurl/lib/ftp.h index b6bfc02..833447b 100644 --- a/Utilities/cmcurl/lib/ftp.h +++ b/Utilities/cmcurl/lib/ftp.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -147,11 +147,10 @@ struct ftp_conn { curl_off_t known_filesize; /* file size is different from -1, if wildcard LIST parsing was done and wc_statemach set it */ - /* newhost must be able to hold a full IP-style address in ASCII, which - in the IPv6 case means 5*8-1 = 39 letters */ -#define NEWHOST_BUFSIZE 48 - char newhost[NEWHOST_BUFSIZE]; /* this is the pair to connect the DATA... */ - unsigned short newport; /* connection to */ + /* newhost is the (allocated) IP addr or host name to connect the data + connection to */ + char *newhost; /* this is the pair to connect the DATA... */ + unsigned short newport; /* connection to */ }; diff --git a/Utilities/cmcurl/lib/ftplistparser.c b/Utilities/cmcurl/lib/ftplistparser.c index 4a46dd1..17e0a66 100644 --- a/Utilities/cmcurl/lib/ftplistparser.c +++ b/Utilities/cmcurl/lib/ftplistparser.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -23,13 +23,13 @@ /** * Now implemented: * - * 1) UNIX version 1 + * 1) Unix version 1 * drwxr-xr-x 1 user01 ftp 512 Jan 29 23:32 prog - * 2) UNIX version 2 + * 2) Unix version 2 * drwxr-xr-x 1 user01 ftp 512 Jan 29 1997 prog - * 3) UNIX version 3 + * 3) Unix version 3 * drwxr-xr-x 1 1 1 512 Jan 29 23:32 prog - * 4) UNIX symlink + * 4) Unix symlink * lrwxr-xr-x 1 user01 ftp 512 Jan 29 23:32 prog -> prog2000 * 5) DOS style * 01-29-97 11:32PM <DIR> prog @@ -49,10 +49,6 @@ #include "ftp.h" #include "ftplistparser.h" #include "curl_fnmatch.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" @@ -191,8 +187,7 @@ struct ftp_parselist_data *Curl_ftp_parselist_data_alloc(void) void Curl_ftp_parselist_data_free(struct ftp_parselist_data **pl_data) { - if(*pl_data) - free(*pl_data); + free(*pl_data); *pl_data = NULL; } @@ -365,7 +360,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb, struct ftp_parselist_data *parser = tmpdata->parser; struct curl_fileinfo *finfo; unsigned long i = 0; - CURLcode rc; + CURLcode result; if(parser->error) { /* error in previous call */ /* scenario: @@ -758,9 +753,9 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb, finfo->b_data[parser->item_offset + parser->item_length - 1] = 0; parser->offsets.filename = parser->item_offset; parser->state.UNIX.main = PL_UNIX_FILETYPE; - rc = ftp_pl_insert_finfo(conn, finfo); - if(rc) { - PL_ERROR(conn, rc); + result = ftp_pl_insert_finfo(conn, finfo); + if(result) { + PL_ERROR(conn, result); return bufflen; } } @@ -770,9 +765,9 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb, finfo->b_data[parser->item_offset + parser->item_length] = 0; parser->offsets.filename = parser->item_offset; parser->state.UNIX.main = PL_UNIX_FILETYPE; - rc = ftp_pl_insert_finfo(conn, finfo); - if(rc) { - PL_ERROR(conn, rc); + result = ftp_pl_insert_finfo(conn, finfo); + if(result) { + PL_ERROR(conn, result); return bufflen; } } @@ -866,9 +861,9 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb, else if(c == '\n') { finfo->b_data[parser->item_offset + parser->item_length - 1] = 0; parser->offsets.symlink_target = parser->item_offset; - rc = ftp_pl_insert_finfo(conn, finfo); - if(rc) { - PL_ERROR(conn, rc); + result = ftp_pl_insert_finfo(conn, finfo); + if(result) { + PL_ERROR(conn, result); return bufflen; } parser->state.UNIX.main = PL_UNIX_FILETYPE; @@ -878,9 +873,9 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb, if(c == '\n') { finfo->b_data[parser->item_offset + parser->item_length - 1] = 0; parser->offsets.symlink_target = parser->item_offset; - rc = ftp_pl_insert_finfo(conn, finfo); - if(rc) { - PL_ERROR(conn, rc); + result = ftp_pl_insert_finfo(conn, finfo); + if(result) { + PL_ERROR(conn, result); return bufflen; } parser->state.UNIX.main = PL_UNIX_FILETYPE; @@ -1011,9 +1006,9 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb, parser->offsets.filename = parser->item_offset; finfo->b_data[finfo->b_used - 1] = 0; parser->offsets.filename = parser->item_offset; - rc = ftp_pl_insert_finfo(conn, finfo); - if(rc) { - PL_ERROR(conn, rc); + result = ftp_pl_insert_finfo(conn, finfo); + if(result) { + PL_ERROR(conn, result); return bufflen; } parser->state.NT.main = PL_WINNT_DATE; @@ -1023,9 +1018,9 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb, case PL_WINNT_FILENAME_WINEOL: if(c == '\n') { parser->offsets.filename = parser->item_offset; - rc = ftp_pl_insert_finfo(conn, finfo); - if(rc) { - PL_ERROR(conn, rc); + result = ftp_pl_insert_finfo(conn, finfo); + if(result) { + PL_ERROR(conn, result); return bufflen; } parser->state.NT.main = PL_WINNT_DATE; @@ -1041,7 +1036,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb, } break; default: - return bufflen+1; + return bufflen + 1; } i++; diff --git a/Utilities/cmcurl/lib/getinfo.c b/Utilities/cmcurl/lib/getinfo.c index 8905d36..910f520 100644 --- a/Utilities/cmcurl/lib/getinfo.c +++ b/Utilities/cmcurl/lib/getinfo.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -27,12 +27,12 @@ #include "urldata.h" #include "getinfo.h" -#include "curl_memory.h" #include "vtls/vtls.h" #include "connect.h" /* Curl_getconnectinfo() */ #include "progress.h" -/* Make this the last #include */ +/* The last #include files should be: */ +#include "curl_memory.h" #include "memdebug.h" /* @@ -42,7 +42,7 @@ CURLcode Curl_initinfo(struct SessionHandle *data) { struct Progress *pro = &data->progress; - struct PureInfo *info =&data->info; + struct PureInfo *info = &data->info; pro->t_nslookup = 0; pro->t_connect = 0; @@ -58,8 +58,7 @@ CURLcode Curl_initinfo(struct SessionHandle *data) info->filetime = -1; /* -1 is an illegal time and thus means unknown */ info->timecond = FALSE; - if(info->contenttype) - free(info->contenttype); + free(info->contenttype); info->contenttype = NULL; info->header_size = 0; @@ -116,6 +115,7 @@ static CURLcode getinfo_char(struct SessionHandle *data, CURLINFO info, default: return CURLE_BAD_FUNCTION_ARGUMENT; } + return CURLE_OK; } @@ -202,6 +202,7 @@ static CURLcode getinfo_long(struct SessionHandle *data, CURLINFO info, default: return CURLE_BAD_FUNCTION_ARGUMENT; } + return CURLE_OK; } @@ -254,6 +255,7 @@ static CURLcode getinfo_double(struct SessionHandle *data, CURLINFO info, default: return CURLE_BAD_FUNCTION_ARGUMENT; } + return CURLE_OK; } @@ -261,8 +263,8 @@ static CURLcode getinfo_slist(struct SessionHandle *data, CURLINFO info, struct curl_slist **param_slistp) { union { - struct curl_certinfo * to_certinfo; - struct curl_slist * to_slist; + struct curl_certinfo *to_certinfo; + struct curl_slist *to_slist; } ptr; switch(info) { @@ -303,7 +305,7 @@ static CURLcode getinfo_slist(struct SessionHandle *data, CURLINFO info, break; /* no SSL session found */ /* Return the TLS session information from the relevant backend */ -#ifdef USE_SSLEAY +#ifdef USE_OPENSSL internals = conn->ssl[sockindex].ctx; #endif #ifdef USE_GNUTLS @@ -312,9 +314,6 @@ static CURLcode getinfo_slist(struct SessionHandle *data, CURLINFO info, #ifdef USE_NSS internals = conn->ssl[sockindex].handle; #endif -#ifdef USE_QSOSSL - internals = conn->ssl[sockindex].handle; -#endif #ifdef USE_GSKIT internals = conn->ssl[sockindex].handle; #endif @@ -331,22 +330,23 @@ static CURLcode getinfo_slist(struct SessionHandle *data, CURLINFO info, default: return CURLE_BAD_FUNCTION_ARGUMENT; } + return CURLE_OK; } CURLcode Curl_getinfo(struct SessionHandle *data, CURLINFO info, ...) { va_list arg; - long *param_longp=NULL; - double *param_doublep=NULL; - char **param_charp=NULL; - struct curl_slist **param_slistp=NULL; + long *param_longp = NULL; + double *param_doublep = NULL; + char **param_charp = NULL; + struct curl_slist **param_slistp = NULL; int type; /* default return code is to error out! */ - CURLcode ret = CURLE_BAD_FUNCTION_ARGUMENT; + CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT; if(!data) - return ret; + return result; va_start(arg, info); @@ -354,28 +354,29 @@ CURLcode Curl_getinfo(struct SessionHandle *data, CURLINFO info, ...) switch(type) { case CURLINFO_STRING: param_charp = va_arg(arg, char **); - if(NULL != param_charp) - ret = getinfo_char(data, info, param_charp); + if(param_charp) + result = getinfo_char(data, info, param_charp); break; case CURLINFO_LONG: param_longp = va_arg(arg, long *); - if(NULL != param_longp) - ret = getinfo_long(data, info, param_longp); + if(param_longp) + result = getinfo_long(data, info, param_longp); break; case CURLINFO_DOUBLE: param_doublep = va_arg(arg, double *); - if(NULL != param_doublep) - ret = getinfo_double(data, info, param_doublep); + if(param_doublep) + result = getinfo_double(data, info, param_doublep); break; case CURLINFO_SLIST: param_slistp = va_arg(arg, struct curl_slist **); - if(NULL != param_slistp) - ret = getinfo_slist(data, info, param_slistp); + if(param_slistp) + result = getinfo_slist(data, info, param_slistp); break; default: break; } va_end(arg); - return ret; + + return result; } diff --git a/Utilities/cmcurl/lib/gopher.c b/Utilities/cmcurl/lib/gopher.c index b1dd65f..954cad8 100644 --- a/Utilities/cmcurl/lib/gopher.c +++ b/Utilities/cmcurl/lib/gopher.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -36,10 +36,6 @@ #include "select.h" #include "url.h" #include "warnless.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" @@ -121,10 +117,10 @@ static CURLcode gopher_do(struct connectdata *conn, bool *done) for(;;) { result = Curl_write(conn, sockfd, sel, k, &amount); - if(CURLE_OK == result) { /* Which may not have written it all! */ + if(!result) { /* Which may not have written it all! */ result = Curl_client_write(conn, CLIENTWRITE_HEADER, sel, amount); if(result) { - Curl_safefree(sel_org); + free(sel_org); return result; } k -= amount; @@ -134,7 +130,7 @@ static CURLcode gopher_do(struct connectdata *conn, bool *done) } else { failf(data, "Failed sending Gopher request"); - Curl_safefree(sel_org); + free(sel_org); return result; } /* Don't busyloop. The entire loop thing is a work-around as it causes a @@ -149,12 +145,12 @@ static CURLcode gopher_do(struct connectdata *conn, bool *done) Curl_socket_ready(CURL_SOCKET_BAD, sockfd, 100); } - Curl_safefree(sel_org); + free(sel_org); /* We can use Curl_sendf to send the terminal \r\n relatively safely and save allocing another string/doing another _write loop. */ result = Curl_sendf(sockfd, conn, "\r\n"); - if(result != CURLE_OK) { + if(result) { failf(data, "Failed sending Gopher request"); return result; } diff --git a/Utilities/cmcurl/lib/hash.c b/Utilities/cmcurl/lib/hash.c index 4a12e1a..c46760a 100644 --- a/Utilities/cmcurl/lib/hash.c +++ b/Utilities/cmcurl/lib/hash.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -24,10 +24,6 @@ #include "hash.h" #include "llist.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" @@ -93,32 +89,6 @@ Curl_hash_init(struct curl_hash *h, } } -struct curl_hash * -Curl_hash_alloc(int slots, - hash_function hfunc, - comp_function comparator, - curl_hash_dtor dtor) -{ - struct curl_hash *h; - - if(!slots || !hfunc || !comparator ||!dtor) { - return NULL; /* failure */ - } - - h = malloc(sizeof(struct curl_hash)); - if(h) { - if(Curl_hash_init(h, slots, hfunc, comparator, dtor)) { - /* failure */ - free(h); - h = NULL; - } - } - - return h; -} - - - static struct curl_hash_element * mk_hash_element(const void *key, size_t key_len, const void *p) { @@ -242,8 +212,11 @@ Curl_hash_apply(curl_hash *h, void *user, } #endif +/* Destroys all the entries in the given hash and resets its attributes, + * prepping the given hash for [static|dynamic] deallocation. + */ void -Curl_hash_clean(struct curl_hash *h) +Curl_hash_destroy(struct curl_hash *h) { int i; @@ -257,6 +230,17 @@ Curl_hash_clean(struct curl_hash *h) h->slots = 0; } +/* Removes all the entries in the given hash. + * + * @unittest: 1602 + */ +void +Curl_hash_clean(struct curl_hash *h) +{ + Curl_hash_clean_with_criterium(h, NULL, NULL); +} + +/* Cleans all entries that pass the comp function criteria. */ void Curl_hash_clean_with_criterium(struct curl_hash *h, void *user, int (*comp)(void *, void *)) @@ -276,7 +260,7 @@ Curl_hash_clean_with_criterium(struct curl_hash *h, void *user, struct curl_hash_element *he = le->ptr; lnext = le->next; /* ask the callback function if we shall remove this entry or not */ - if(comp(user, he->ptr)) { + if(comp == NULL || comp(user, he->ptr)) { Curl_llist_remove(list, le, (void *) h); --h->size; /* one less entry in the hash now */ } @@ -285,17 +269,6 @@ Curl_hash_clean_with_criterium(struct curl_hash *h, void *user, } } -void -Curl_hash_destroy(struct curl_hash *h) -{ - if(!h) - return; - - Curl_hash_clean(h); - - free(h); -} - size_t Curl_hash_str(void* key, size_t key_length, size_t slots_num) { const char* key_str = (const char *) key; @@ -310,16 +283,11 @@ size_t Curl_hash_str(void* key, size_t key_length, size_t slots_num) return (h % slots_num); } -size_t Curl_str_key_compare(void*k1, size_t key1_len, void*k2, size_t key2_len) +size_t Curl_str_key_compare(void *k1, size_t key1_len, + void *k2, size_t key2_len) { - char *key1 = (char *)k1; - char *key2 = (char *)k2; - - if(key1_len == key2_len && - *key1 == *key2 && - memcmp(key1, key2, key1_len) == 0) { + if((key1_len == key2_len) && !memcmp(k1, k2, key1_len)) return 1; - } return 0; } diff --git a/Utilities/cmcurl/lib/hash.h b/Utilities/cmcurl/lib/hash.h index aa935d4..b13a236 100644 --- a/Utilities/cmcurl/lib/hash.h +++ b/Utilities/cmcurl/lib/hash.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -74,22 +74,16 @@ int Curl_hash_init(struct curl_hash *h, comp_function comparator, curl_hash_dtor dtor); -struct curl_hash *Curl_hash_alloc(int slots, - hash_function hfunc, - comp_function comparator, - curl_hash_dtor dtor); - void *Curl_hash_add(struct curl_hash *h, void *key, size_t key_len, void *p); int Curl_hash_delete(struct curl_hash *h, void *key, size_t key_len); void *Curl_hash_pick(struct curl_hash *, void * key, size_t key_len); void Curl_hash_apply(struct curl_hash *h, void *user, void (*cb)(void *user, void *ptr)); int Curl_hash_count(struct curl_hash *h); +void Curl_hash_destroy(struct curl_hash *h); void Curl_hash_clean(struct curl_hash *h); void Curl_hash_clean_with_criterium(struct curl_hash *h, void *user, int (*comp)(void *, void *)); -void Curl_hash_destroy(struct curl_hash *h); - size_t Curl_hash_str(void* key, size_t key_length, size_t slots_num); size_t Curl_str_key_compare(void*k1, size_t key1_len, void*k2, size_t key2_len); diff --git a/Utilities/cmcurl/lib/hmac.c b/Utilities/cmcurl/lib/hmac.c index dace820..0d2d5f4 100644 --- a/Utilities/cmcurl/lib/hmac.c +++ b/Utilities/cmcurl/lib/hmac.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -27,10 +27,6 @@ #ifndef CURL_DISABLE_CRYPTO_AUTH #include "curl_hmac.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" diff --git a/Utilities/cmcurl/lib/hostasyn.c b/Utilities/cmcurl/lib/hostasyn.c index 8151b67..17b8be0 100644 --- a/Utilities/cmcurl/lib/hostasyn.c +++ b/Utilities/cmcurl/lib/hostasyn.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -47,10 +47,6 @@ #include "share.h" #include "strerror.h" #include "url.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" @@ -75,7 +71,7 @@ CURLcode Curl_addrinfo_callback(struct connectdata *conn, struct Curl_addrinfo *ai) { struct Curl_dns_entry *dns = NULL; - CURLcode rc = CURLE_OK; + CURLcode result = CURLE_OK; conn->async.status = status; @@ -92,14 +88,14 @@ CURLcode Curl_addrinfo_callback(struct connectdata *conn, if(!dns) { /* failed to store, cleanup and return error */ Curl_freeaddrinfo(ai); - rc = CURLE_OUT_OF_MEMORY; + result = CURLE_OUT_OF_MEMORY; } if(data->share) Curl_share_unlock(data, CURL_LOCK_DATA_DNS); } else { - rc = CURLE_OUT_OF_MEMORY; + result = CURLE_OUT_OF_MEMORY; } } @@ -110,9 +106,9 @@ CURLcode Curl_addrinfo_callback(struct connectdata *conn, async struct */ conn->async.done = TRUE; - /* ipv4: The input hostent struct will be freed by ares when we return from + /* IPv4: The input hostent struct will be freed by ares when we return from this function */ - return rc; + return result; } /* Call this function after Curl_connect() has returned async=TRUE and @@ -123,21 +119,21 @@ CURLcode Curl_addrinfo_callback(struct connectdata *conn, CURLcode Curl_async_resolved(struct connectdata *conn, bool *protocol_done) { - CURLcode code; + CURLcode result; if(conn->async.dns) { conn->dns_entry = conn->async.dns; conn->async.dns = NULL; } - code = Curl_setup_conn(conn, protocol_done); + result = Curl_setup_conn(conn, protocol_done); - if(code) + if(result) /* We're not allowed to return failure with memory left allocated in the connectdata struct, free those here */ Curl_disconnect(conn, FALSE); /* close the connection */ - return code; + return result; } /* diff --git a/Utilities/cmcurl/lib/hostcheck.c b/Utilities/cmcurl/lib/hostcheck.c index 42eb2ee..62a26e4 100644 --- a/Utilities/cmcurl/lib/hostcheck.c +++ b/Utilities/cmcurl/lib/hostcheck.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -22,8 +22,7 @@ #include "curl_setup.h" -#if defined(USE_SSLEAY) || defined(USE_AXTLS) || defined(USE_QSOSSL) || \ - defined(USE_GSKIT) +#if defined(USE_OPENSSL) || defined(USE_AXTLS) || defined(USE_GSKIT) /* these backends use functions from this file */ #ifdef HAVE_NETINET_IN_H @@ -145,4 +144,4 @@ int Curl_cert_hostcheck(const char *match_pattern, const char *hostname) return res; } -#endif /* SSLEAY or AXTLS or QSOSSL or GSKIT */ +#endif /* OPENSSL or AXTLS or GSKIT */ diff --git a/Utilities/cmcurl/lib/hostip.c b/Utilities/cmcurl/lib/hostip.c index 73b3f82..82f3897 100644 --- a/Utilities/cmcurl/lib/hostip.c +++ b/Utilities/cmcurl/lib/hostip.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -56,10 +56,7 @@ #include "url.h" #include "inet_ntop.h" #include "warnless.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - +#include "curl_printf.h" #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" @@ -98,8 +95,8 @@ * hostip.c - method-independent resolver functions and utility functions * hostasyn.c - functions for asynchronous name resolves * hostsyn.c - functions for synchronous name resolves - * hostip4.c - ipv4-specific functions - * hostip6.c - ipv6-specific functions + * hostip4.c - IPv4 specific functions + * hostip6.c - IPv6 specific functions * * The two asynchronous name resolver backends are implemented in: * asyn-ares.c - functions for ares-using name resolves @@ -140,11 +137,7 @@ struct curl_hash *Curl_global_host_cache_init(void) void Curl_global_host_cache_dtor(void) { if(host_cache_initialized) { - /* first make sure that any custom "CURLOPT_RESOLVE" names are - cleared off */ - Curl_hostcache_clean(NULL, &hostname_cache); - /* then free the remaining hash completely */ - Curl_hash_clean(&hostname_cache); + Curl_hash_destroy(&hostname_cache); host_cache_initialized = 0; } } @@ -237,7 +230,8 @@ hostcache_timestamp_remove(void *datap, void *hc) (struct hostcache_prune_data *) datap; struct Curl_dns_entry *c = (struct Curl_dns_entry *) hc; - return !c->inuse && (data->now - c->timestamp >= data->cache_timeout); + return (0 != c->timestamp) + && (data->now - c->timestamp >= data->cache_timeout); } /* @@ -283,40 +277,54 @@ void Curl_hostcache_prune(struct SessionHandle *data) Curl_share_unlock(data, CURL_LOCK_DATA_DNS); } -/* - * Check if the entry should be pruned. Assumes a locked cache. - */ -static int -remove_entry_if_stale(struct SessionHandle *data, struct Curl_dns_entry *dns) +#ifdef HAVE_SIGSETJMP +/* Beware this is a global and unique instance. This is used to store the + return address that we can jump back to from inside a signal handler. This + is not thread-safe stuff. */ +sigjmp_buf curl_jmpenv; +#endif + +/* lookup address, returns entry if found and not stale */ +static struct Curl_dns_entry * +fetch_addr(struct connectdata *conn, + const char *hostname, + int port) { - struct hostcache_prune_data user; + char *entry_id = NULL; + struct Curl_dns_entry *dns = NULL; + size_t entry_len; + struct SessionHandle *data = conn->data; - if(!dns || (data->set.dns_cache_timeout == -1) || !data->dns.hostcache || - dns->inuse) - /* cache forever means never prune, and NULL hostcache means we can't do - it, if it still is in use then we leave it */ - return 0; + /* Create an entry id, based upon the hostname and port */ + entry_id = create_hostcache_id(hostname, port); + /* If we can't create the entry id, fail */ + if(!entry_id) + return dns; - time(&user.now); - user.cache_timeout = data->set.dns_cache_timeout; + entry_len = strlen(entry_id); - if(!hostcache_timestamp_remove(&user,dns) ) - return 0; + /* See if its already in our dns cache */ + dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len+1); - Curl_hash_clean_with_criterium(data->dns.hostcache, - (void *) &user, - hostcache_timestamp_remove); + 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; - return 1; -} + time(&user.now); + user.cache_timeout = data->set.dns_cache_timeout; + 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); + } + } -#ifdef HAVE_SIGSETJMP -/* Beware this is a global and unique instance. This is used to store the - return address that we can jump back to from inside a signal handler. This - is not thread-safe stuff. */ -sigjmp_buf curl_jmpenv; -#endif + /* free the allocated entry_id again */ + free(entry_id); + + return dns; +} /* * Curl_fetch_addr() fetches a 'Curl_dns_entry' already in the DNS cache. @@ -328,35 +336,27 @@ sigjmp_buf curl_jmpenv; * lookups for the same hostname requested by different handles. * * Returns the Curl_dns_entry entry pointer or NULL if not in the cache. + * + * The returned data *MUST* be "unlocked" with Curl_resolv_unlock() after + * use, or we'll leak memory! */ struct Curl_dns_entry * Curl_fetch_addr(struct connectdata *conn, const char *hostname, - int port, int *stale) + int port) { - char *entry_id = NULL; - struct Curl_dns_entry *dns = NULL; - size_t entry_len; struct SessionHandle *data = conn->data; + struct Curl_dns_entry *dns = NULL; - /* Create an entry id, based upon the hostname and port */ - entry_id = create_hostcache_id(hostname, port); - /* If we can't create the entry id, fail */ - if(!entry_id) - return dns; - - entry_len = strlen(entry_id); + if(data->share) + 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 = fetch_addr(conn, hostname, port); - /* free the allocated entry_id again */ - free(entry_id); + if(dns) dns->inuse++; /* we use it! */ - /* See whether the returned entry is stale. Done before we release lock */ - *stale = remove_entry_if_stale(data, dns); - if(*stale) - dns = NULL; /* the memory deallocation is being handled by the hash */ + if(data->share) + Curl_share_unlock(data, CURL_LOCK_DATA_DNS); return dns; } @@ -395,11 +395,11 @@ Curl_cache_addr(struct SessionHandle *data, return NULL; } - dns->inuse = 0; /* init to not used */ + dns->inuse = 1; /* the cache has the first reference */ dns->addr = addr; /* this is the address(es) */ time(&dns->timestamp); if(dns->timestamp == 0) - dns->timestamp = 1; /* zero indicates that entry isn't in hash table */ + 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, @@ -448,21 +448,17 @@ int Curl_resolv(struct connectdata *conn, struct Curl_dns_entry *dns = NULL; struct SessionHandle *data = conn->data; CURLcode result; - int stale, rc = CURLRESOLV_ERROR; /* default to failure */ + int rc = CURLRESOLV_ERROR; /* default to failure */ *entry = NULL; if(data->share) Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); - dns = Curl_fetch_addr(conn, hostname, port, &stale); - - infof(data, "Hostname was %sfound in DNS cache\n", dns||stale?"":"NOT "); - if(stale) - infof(data, "Hostname in DNS cache was stale, zapped\n"); - + dns = fetch_addr(conn, hostname, port); if(dns) { + infof(data, "Hostname %s was found in DNS cache\n", hostname); dns->inuse++; /* we use it! */ rc = CURLRESOLV_RESOLVED; } @@ -611,32 +607,6 @@ int Curl_resolv_timeout(struct connectdata *conn, we want to wait less than one second we must bail out already now. */ return CURLRESOLV_TIMEDOUT; - /************************************************************* - * Set signal handler to catch SIGALRM - * Store the old value to be able to set it back later! - *************************************************************/ -#ifdef HAVE_SIGACTION - sigaction(SIGALRM, NULL, &sigact); - keep_sigact = sigact; - keep_copysig = TRUE; /* yes, we have a copy */ - sigact.sa_handler = alarmfunc; -#ifdef SA_RESTART - /* HPUX doesn't have SA_RESTART but defaults to that behaviour! */ - sigact.sa_flags &= ~SA_RESTART; -#endif - /* now set the new struct */ - sigaction(SIGALRM, &sigact, NULL); -#else /* HAVE_SIGACTION */ - /* no sigaction(), revert to the much lamer signal() */ -#ifdef HAVE_SIGNAL - keep_sigact = signal(SIGALRM, alarmfunc); -#endif -#endif /* HAVE_SIGACTION */ - - /* alarm() makes a signal get sent when the timeout fires off, and that - will abort system calls */ - prev_alarm = alarm(curlx_sltoui(timeout/1000L)); - /* This allows us to time-out from the name resolver, as the timeout will generate a signal and we will siglongjmp() from that here. This technique has problems (see alarmfunc). @@ -649,6 +619,33 @@ int Curl_resolv_timeout(struct connectdata *conn, rc = CURLRESOLV_ERROR; goto clean_up; } + else { + /************************************************************* + * Set signal handler to catch SIGALRM + * Store the old value to be able to set it back later! + *************************************************************/ +#ifdef HAVE_SIGACTION + sigaction(SIGALRM, NULL, &sigact); + keep_sigact = sigact; + keep_copysig = TRUE; /* yes, we have a copy */ + sigact.sa_handler = alarmfunc; +#ifdef SA_RESTART + /* HPUX doesn't have SA_RESTART but defaults to that behaviour! */ + sigact.sa_flags &= ~SA_RESTART; +#endif + /* now set the new struct */ + sigaction(SIGALRM, &sigact, NULL); +#else /* HAVE_SIGACTION */ + /* no sigaction(), revert to the much lamer signal() */ +#ifdef HAVE_SIGNAL + keep_sigact = signal(SIGALRM, alarmfunc); +#endif +#endif /* HAVE_SIGACTION */ + + /* alarm() makes a signal get sent when the timeout fires off, and that + will abort system calls */ + prev_alarm = alarm(curlx_sltoui(timeout/1000L)); + } #else #ifndef CURLRES_ASYNCH @@ -720,54 +717,37 @@ clean_up: */ void Curl_resolv_unlock(struct SessionHandle *data, struct Curl_dns_entry *dns) { - DEBUGASSERT(dns && (dns->inuse>0)); - if(data && data->share) Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); - dns->inuse--; - /* only free if nobody is using AND it is not in hostcache (timestamp == - 0) */ - if(dns->inuse == 0 && dns->timestamp == 0) { - Curl_freeaddrinfo(dns->addr); - free(dns); - } + freednsentry(dns); if(data && data->share) Curl_share_unlock(data, CURL_LOCK_DATA_DNS); } /* - * File-internal: free a cache dns entry. + * File-internal: release cache dns entry reference, free if inuse drops to 0 */ static void freednsentry(void *freethis) { - struct Curl_dns_entry *p = (struct Curl_dns_entry *) freethis; + struct Curl_dns_entry *dns = (struct Curl_dns_entry *) freethis; + DEBUGASSERT(dns && (dns->inuse>0)); - /* mark the entry as not in hostcache */ - p->timestamp = 0; - if(p->inuse == 0) { - Curl_freeaddrinfo(p->addr); - free(p); + dns->inuse--; + if(dns->inuse == 0) { + Curl_freeaddrinfo(dns->addr); + free(dns); } } /* - * Curl_mk_dnscache() creates a new DNS cache and returns the handle for it. + * Curl_mk_dnscache() inits a new DNS cache and returns success/failure. */ -struct curl_hash *Curl_mk_dnscache(void) +int Curl_mk_dnscache(struct curl_hash *hash) { - return Curl_hash_alloc(7, Curl_hash_str, Curl_str_key_compare, freednsentry); -} - -static int hostcache_inuse(void *data, void *hc) -{ - struct Curl_dns_entry *c = (struct Curl_dns_entry *) hc; - - if(c->inuse == 1) - Curl_resolv_unlock(data, c); - - return 1; /* free all entries */ + return Curl_hash_init(hash, 7, Curl_hash_str, Curl_str_key_compare, + freednsentry); } /* @@ -780,11 +760,13 @@ static int hostcache_inuse(void *data, void *hc) void Curl_hostcache_clean(struct SessionHandle *data, struct curl_hash *hash) { - /* Entries added to the hostcache with the CURLOPT_RESOLVE function are - * still present in the cache with the inuse counter set to 1. Detect them - * and cleanup! - */ - Curl_hash_clean_with_criterium(hash, data, hostcache_inuse); + if(data && data->share) + Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); + + Curl_hash_clean(hash); + + if(data && data->share) + Curl_share_unlock(data, CURL_LOCK_DATA_DNS); } @@ -799,18 +781,52 @@ CURLcode Curl_loadhostpairs(struct SessionHandle *data) if(!hostp->data) continue; if(hostp->data[0] == '-') { - /* TODO: mark an entry for removal */ + char *entry_id; + size_t entry_len; + + if(2 != sscanf(hostp->data + 1, "%255[^:]:%d", hostname, &port)) { + infof(data, "Couldn't parse CURLOPT_RESOLVE removal entry '%s'!\n", + hostp->data); + continue; + } + + /* Create an entry id, based upon the hostname and port */ + entry_id = create_hostcache_id(hostname, port); + /* If we can't create the entry id, fail */ + if(!entry_id) { + return CURLE_OUT_OF_MEMORY; + } + + entry_len = strlen(entry_id); + + if(data->share) + 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); + + if(data->share) + Curl_share_unlock(data, CURL_LOCK_DATA_DNS); + + /* free the allocated entry_id again */ + free(entry_id); } - else if(3 == sscanf(hostp->data, "%255[^:]:%d:%255s", hostname, &port, - address)) { + else { struct Curl_dns_entry *dns; Curl_addrinfo *addr; char *entry_id; size_t entry_len; + if(3 != sscanf(hostp->data, "%255[^:]:%d:%255s", hostname, &port, + address)) { + infof(data, "Couldn't parse CURLOPT_RESOLVE entry '%s'!\n", + hostp->data); + continue; + } + addr = Curl_str2addr(address, port); if(!addr) { - infof(data, "Resolve %s found illegal!\n", hostp->data); + infof(data, "Address in '%s' found illegal!\n", hostp->data); continue; } @@ -833,9 +849,16 @@ CURLcode Curl_loadhostpairs(struct SessionHandle *data) /* free the allocated entry_id again */ free(entry_id); - if(!dns) + if(!dns) { /* if not in the cache already, put this host in the cache */ dns = Curl_cache_addr(data, addr, hostname, port); + if(dns) { + dns->timestamp = 0; /* mark as added by CURLOPT_RESOLVE */ + /* release the returned reference; the cache itself will keep the + * entry alive: */ + dns->inuse--; + } + } else /* this is a duplicate, free it again */ Curl_freeaddrinfo(addr); diff --git a/Utilities/cmcurl/lib/hostip.h b/Utilities/cmcurl/lib/hostip.h index 4404651..d5b44bc 100644 --- a/Utilities/cmcurl/lib/hostip.h +++ b/Utilities/cmcurl/lib/hostip.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -65,11 +65,10 @@ void Curl_global_host_cache_dtor(void); struct Curl_dns_entry { Curl_addrinfo *addr; - /* timestamp == 0 -- entry not in hostcache - timestamp != 0 -- entry is in hostcache */ + /* timestamp == 0 -- CURLOPT_RESOLVE entry, doesn't timeout */ time_t timestamp; - long inuse; /* use-counter, make very sure you decrease this - when you're done using the address you received */ + /* use-counter, use Curl_resolv_unlock to release reference */ + long inuse; }; /* @@ -92,7 +91,7 @@ int Curl_resolv_timeout(struct connectdata *conn, const char *hostname, #ifdef CURLRES_IPV6 /* - * Curl_ipv6works() returns TRUE if ipv6 seems to work. + * Curl_ipv6works() returns TRUE if IPv6 seems to work. */ bool Curl_ipv6works(void); #else @@ -125,8 +124,8 @@ void Curl_resolv_unlock(struct SessionHandle *data, /* for debugging purposes only: */ void Curl_scan_cache_used(void *user, void *ptr); -/* make a new dns cache and return the handle */ -struct curl_hash *Curl_mk_dnscache(void); +/* init a new dns cache and return success */ +int Curl_mk_dnscache(struct curl_hash *hash); /* prune old entries from the DNS cache */ void Curl_hostcache_prune(struct SessionHandle *data); @@ -175,13 +174,14 @@ const char *Curl_printable_address(const Curl_addrinfo *ip, * Curl_fetch_addr() fetches a 'Curl_dns_entry' already in the DNS cache. * * Returns the Curl_dns_entry entry pointer or NULL if not in the cache. + * + * The returned data *MUST* be "unlocked" with Curl_resolv_unlock() after + * use, or we'll leak memory! */ struct Curl_dns_entry * Curl_fetch_addr(struct connectdata *conn, const char *hostname, - int port, - int *stale); - + int port); /* * Curl_cache_addr() stores a 'Curl_addrinfo' struct in the DNS cache. * diff --git a/Utilities/cmcurl/lib/hostip4.c b/Utilities/cmcurl/lib/hostip4.c index 1e39f4a..37b0369 100644 --- a/Utilities/cmcurl/lib/hostip4.c +++ b/Utilities/cmcurl/lib/hostip4.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -48,18 +48,15 @@ #include "strerror.h" #include "url.h" #include "inet_pton.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - +#include "curl_printf.h" #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" /*********************************************************************** - * Only for plain-ipv4 builds + * Only for plain IPv4 builds **********************************************************************/ -#ifdef CURLRES_IPV4 /* plain ipv4 code coming up */ +#ifdef CURLRES_IPV4 /* plain IPv4 code coming up */ /* * Curl_ipvalid() checks what CURL_IPRESOLVE_* requirements that might've * been set and returns TRUE if they are OK. @@ -67,7 +64,7 @@ bool Curl_ipvalid(struct connectdata *conn) { if(conn->ip_version == CURL_IPRESOLVE_V6) - /* an ipv6 address was requested and we can't get/use one */ + /* An IPv6 address was requested and we can't get/use one */ return FALSE; return TRUE; /* OK, proceed */ @@ -76,7 +73,7 @@ bool Curl_ipvalid(struct connectdata *conn) #ifdef CURLRES_SYNCH /* - * Curl_getaddrinfo() - the ipv4 synchronous version. + * Curl_getaddrinfo() - the IPv4 synchronous version. * * The original code to this function was from the Dancer source code, written * by Bjorn Reese, it has since been patched and modified considerably. diff --git a/Utilities/cmcurl/lib/hostip6.c b/Utilities/cmcurl/lib/hostip6.c index 8327004..6ab131a 100644 --- a/Utilities/cmcurl/lib/hostip6.c +++ b/Utilities/cmcurl/lib/hostip6.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -49,16 +49,13 @@ #include "url.h" #include "inet_pton.h" #include "connect.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - +#include "curl_printf.h" #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" /*********************************************************************** - * Only for ipv6-enabled builds + * Only for IPv6-enabled builds **********************************************************************/ #ifdef CURLRES_IPV6 @@ -97,7 +94,7 @@ int curl_dogetnameinfo(GETNAMEINFO_QUAL_ARG1 GETNAMEINFO_TYPE_ARG1 sa, #endif /* defined(CURLDEBUG) && defined(HAVE_GETNAMEINFO) */ /* - * Curl_ipv6works() returns TRUE if ipv6 seems to work. + * Curl_ipv6works() returns TRUE if IPv6 seems to work. */ bool Curl_ipv6works(void) { @@ -109,7 +106,7 @@ bool Curl_ipv6works(void) /* probe to see if we have a working IPv6 stack */ curl_socket_t s = socket(PF_INET6, SOCK_DGRAM, 0); if(s == CURL_SOCKET_BAD) - /* an ipv6 address was requested but we can't get/use one */ + /* an IPv6 address was requested but we can't get/use one */ ipv6_works = 0; else { ipv6_works = 1; @@ -152,7 +149,7 @@ static void dump_addrinfo(struct connectdata *conn, const Curl_addrinfo *ai) #endif /* - * Curl_getaddrinfo() when built ipv6-enabled (non-threading and + * Curl_getaddrinfo() when built IPv6-enabled (non-threading and * non-ares version). * * Returns name information about the given hostname and port number. If @@ -192,7 +189,7 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, } if((pf != PF_INET) && !Curl_ipv6works()) - /* the stack seems to be a non-ipv6 one */ + /* The stack seems to be a non-IPv6 one */ pf = PF_INET; memset(&hints, 0, sizeof(hints)); diff --git a/Utilities/cmcurl/lib/hostsyn.c b/Utilities/cmcurl/lib/hostsyn.c index 4ad3c63..fb1de35 100644 --- a/Utilities/cmcurl/lib/hostsyn.c +++ b/Utilities/cmcurl/lib/hostsyn.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -47,10 +47,6 @@ #include "share.h" #include "strerror.h" #include "url.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" diff --git a/Utilities/cmcurl/lib/http.c b/Utilities/cmcurl/lib/http.c index 35baa34..9817d72 100644 --- a/Utilities/cmcurl/lib/http.c +++ b/Utilities/cmcurl/lib/http.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -63,7 +63,6 @@ #include "share.h" #include "hostip.h" #include "http.h" -#include "curl_memory.h" #include "select.h" #include "parsedate.h" /* for the week day and month names */ #include "strtoofft.h" @@ -73,15 +72,14 @@ #include "http_proxy.h" #include "warnless.h" #include "non-ascii.h" -#include "bundles.h" +#include "conncache.h" #include "pipeline.h" #include "http2.h" #include "connect.h" +#include "curl_printf.h" -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - -/* The last #include file should be: */ +/* The last #include files should be: */ +#include "curl_memory.h" #include "memdebug.h" /* @@ -155,12 +153,18 @@ CURLcode Curl_http_setup_conn(struct connectdata *conn) { /* allocate the HTTP-specific struct for the SessionHandle, only to survive during this request */ + struct HTTP *http; DEBUGASSERT(conn->data->req.protop == NULL); - conn->data->req.protop = calloc(1, sizeof(struct HTTP)); - if(!conn->data->req.protop) + http = calloc(1, sizeof(struct HTTP)); + if(!http) return CURLE_OUT_OF_MEMORY; + conn->data->req.protop = http; + + Curl_http2_setup_conn(conn); + Curl_http2_setup_req(conn->data); + return CURLE_OK; } @@ -279,7 +283,7 @@ static CURLcode http_output_basic(struct connectdata *conn, bool proxy) char **userp; const char *user; const char *pwd; - CURLcode error; + CURLcode result; if(proxy) { userp = &conn->allocptr.proxyuserpwd; @@ -294,16 +298,16 @@ static CURLcode http_output_basic(struct connectdata *conn, bool proxy) snprintf(data->state.buffer, sizeof(data->state.buffer), "%s:%s", user, pwd); - error = Curl_base64_encode(data, - data->state.buffer, strlen(data->state.buffer), - &authorization, &size); - if(error) - return error; + result = Curl_base64_encode(data, + data->state.buffer, strlen(data->state.buffer), + &authorization, &size); + if(result) + return result; if(!authorization) return CURLE_REMOTE_ACCESS_DENIED; - Curl_safefree(*userp); + free(*userp); *userp = aprintf("%sAuthorization: Basic %s\r\n", proxy?"Proxy-":"", authorization); @@ -392,16 +396,21 @@ static CURLcode http_perhapsrewind(struct connectdata *conn) bytessent = http->writebytecount; - if(conn->bits.authneg) + if(conn->bits.authneg) { /* This is a state where we are known to be negotiating and we don't send any data then. */ expectsend = 0; + } + else if(!conn->bits.protoconnstart) { + /* HTTP CONNECT in progress: there is no body */ + expectsend = 0; + } else { /* figure out how much data we are expected to send */ switch(data->set.httpreq) { case HTTPREQ_POST: - if(data->set.postfieldsize != -1) - expectsend = data->set.postfieldsize; + if(data->state.infilesize != -1) + expectsend = data->state.infilesize; else if(data->set.postfields) expectsend = (curl_off_t)strlen(data->set.postfields); break; @@ -420,6 +429,7 @@ static CURLcode http_perhapsrewind(struct connectdata *conn) conn->bits.rewindaftersend = FALSE; /* default */ if((expectsend == -1) || (expectsend > bytessent)) { +#if defined(USE_NTLM) /* There is still data left to send */ if((data->state.authproxy.picked == CURLAUTH_NTLM) || (data->state.authhost.picked == CURLAUTH_NTLM) || @@ -439,6 +449,7 @@ static CURLcode http_perhapsrewind(struct connectdata *conn) return CURLE_OK; } + if(conn->bits.close) /* this is already marked to get closed */ return CURLE_OK; @@ -447,9 +458,9 @@ static CURLcode http_perhapsrewind(struct connectdata *conn) CURL_FORMAT_CURL_OFF_T " bytes\n", (curl_off_t)(expectsend - bytessent)); } +#endif - /* This is not NTLM or many bytes left to send: close - */ + /* This is not NTLM or many bytes left to send: close */ connclose(conn, "Mid-auth HTTP and much data left to send"); data->req.size = 0; /* don't download any more than 0 bytes */ @@ -476,7 +487,7 @@ CURLcode Curl_http_auth_act(struct connectdata *conn) struct SessionHandle *data = conn->data; bool pickhost = FALSE; bool pickproxy = FALSE; - CURLcode code = CURLE_OK; + CURLcode result = CURLE_OK; if(100 <= data->req.httpcode && 199 >= data->req.httpcode) /* this is a transient response code, ignore */ @@ -512,9 +523,9 @@ CURLcode Curl_http_auth_act(struct connectdata *conn) if((data->set.httpreq != HTTPREQ_GET) && (data->set.httpreq != HTTPREQ_HEAD) && !conn->bits.rewindaftersend) { - code = http_perhapsrewind(conn); - if(code) - return code; + result = http_perhapsrewind(conn); + if(result) + return result; } } @@ -536,10 +547,10 @@ CURLcode Curl_http_auth_act(struct connectdata *conn) if(http_should_fail(conn)) { failf (data, "The requested URL returned error: %d", data->req.httpcode); - code = CURLE_HTTP_RETURNED_ERROR; + result = CURLE_HTTP_RETURNED_ERROR; } - return code; + return result; } @@ -554,9 +565,11 @@ output_auth_headers(struct connectdata *conn, const char *path, bool proxy) { - struct SessionHandle *data = conn->data; - const char *auth=NULL; + const char *auth = NULL; CURLcode result = CURLE_OK; +#if defined(USE_SPNEGO) || !defined(CURL_DISABLE_VERBOSE_STRINGS) + struct SessionHandle *data = conn->data; +#endif #ifdef USE_SPNEGO struct negotiatedata *negdata = proxy? &data->state.proxyneg:&data->state.negotiate; @@ -672,7 +685,7 @@ Curl_http_output_auth(struct connectdata *conn, if((conn->bits.httpproxy && conn->bits.proxy_user_passwd) || conn->bits.user_passwd) - /* continue please */ ; + /* continue please */; else { authhost->done = TRUE; authproxy->done = TRUE; @@ -773,14 +786,13 @@ CURLcode Curl_http_input_auth(struct connectdata *conn, bool proxy, while(*auth) { #ifdef USE_SPNEGO if(checkprefix("Negotiate", auth)) { - int neg; *availp |= CURLAUTH_NEGOTIATE; authp->avail |= CURLAUTH_NEGOTIATE; if(authp->picked == CURLAUTH_NEGOTIATE) { if(negdata->state == GSS_AUTHSENT || negdata->state == GSS_AUTHNONE) { - neg = Curl_input_negotiate(conn, proxy, auth); - if(neg == 0) { + CURLcode result = Curl_input_negotiate(conn, proxy, auth); + if(!result) { DEBUGASSERT(!data->req.newurl); data->req.newurl = strdup(data->change.url); if(!data->req.newurl) @@ -804,9 +816,8 @@ CURLcode Curl_http_input_auth(struct connectdata *conn, bool proxy, if(authp->picked == CURLAUTH_NTLM || authp->picked == CURLAUTH_NTLM_WB) { /* NTLM authentication is picked and activated */ - CURLcode ntlm = - Curl_input_ntlm(conn, proxy, auth); - if(CURLE_OK == ntlm) { + CURLcode result = Curl_input_ntlm(conn, proxy, auth); + if(!result) { data->state.authproblem = FALSE; #ifdef NTLM_WB_ENABLED if(authp->picked == CURLAUTH_NTLM_WB) { @@ -844,7 +855,7 @@ CURLcode Curl_http_input_auth(struct connectdata *conn, bool proxy, infof(data, "Ignoring duplicate digest auth header.\n"); } else { - CURLdigest dig; + CURLcode result; *availp |= CURLAUTH_DIGEST; authp->avail |= CURLAUTH_DIGEST; @@ -852,9 +863,8 @@ CURLcode Curl_http_input_auth(struct connectdata *conn, bool proxy, * authentication isn't activated yet, as we need to store the * incoming data from this header in case we are gonna use * Digest. */ - dig = Curl_input_digest(conn, proxy, auth); - - if(CURLDIGEST_FINE != dig) { + result = Curl_input_digest(conn, proxy, auth); + if(result) { infof(data, "Authentication problem. Ignoring this.\n"); data->state.authproblem = TRUE; } @@ -991,8 +1001,8 @@ static size_t readmoredata(char *buffer, /* move backup data into focus and continue on that */ http->postdata = http->backup.postdata; http->postsize = http->backup.postsize; - conn->fread_func = http->backup.fread_func; - conn->fread_in = http->backup.fread_in; + conn->data->set.fread_func = http->backup.fread_func; + conn->data->set.in = http->backup.fread_in; http->sending++; /* move one step up */ @@ -1023,6 +1033,16 @@ Curl_send_buffer *Curl_add_buffer_init(void) } /* + * Curl_add_buffer_free() frees all associated resources. + */ +void Curl_add_buffer_free(Curl_send_buffer *buff) +{ + if(buff) /* deal with NULL input */ + free(buff->buffer); + free(buff); +} + +/* * Curl_add_buffer_send() sends a header buffer and frees all associated * memory. Body data may be appended to the header data if desired. * @@ -1041,7 +1061,7 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in, { ssize_t amount; - CURLcode res; + CURLcode result; char *ptr; size_t size; struct HTTP *http = conn->data->req.protop; @@ -1064,14 +1084,12 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in, DEBUGASSERT(size > included_body_bytes); - res = Curl_convert_to_network(conn->data, ptr, headersize); + result = Curl_convert_to_network(conn->data, ptr, headersize); /* Curl_convert_to_network calls failf if unsuccessful */ - if(res) { + if(result) { /* conversion failed, free memory and return to the caller */ - if(in->buffer) - free(in->buffer); - free(in); - return res; + Curl_add_buffer_free(in); + return result; } @@ -1096,9 +1114,9 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in, else sendsize = size; - res = Curl_write(conn, sockfd, ptr, sendsize, &amount); + result = Curl_write(conn, sockfd, ptr, sendsize, &amount); - if(CURLE_OK == res) { + if(!result) { /* * Note that we may not send the entire chunk at once, and we have a set * number of data bytes at the end of the big buffer (out of which we may @@ -1139,14 +1157,14 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in, ptr = in->buffer + amount; /* backup the currently set pointers */ - http->backup.fread_func = conn->fread_func; - http->backup.fread_in = conn->fread_in; + http->backup.fread_func = conn->data->set.fread_func; + http->backup.fread_in = conn->data->set.in; http->backup.postdata = http->postdata; http->backup.postsize = http->postsize; /* set the new pointers for the request-sending */ - conn->fread_func = (curl_read_callback)readmoredata; - conn->fread_in = (void *)conn; + conn->data->set.fread_func = (curl_read_callback)readmoredata; + conn->data->set.in = (void *)conn; http->postdata = ptr; http->postsize = (curl_off_t)size; @@ -1169,14 +1187,12 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in, */ return CURLE_SEND_ERROR; else - conn->writechannel_inuse = FALSE; + Curl_pipeline_leave_write(conn); } } - if(in->buffer) - free(in->buffer); - free(in); + Curl_add_buffer_free(in); - return res; + return result; } @@ -1197,8 +1213,7 @@ CURLcode Curl_add_bufferf(Curl_send_buffer *in, const char *fmt, ...) return result; } /* If we failed, we cleanup the whole buffer and return error */ - if(in->buffer) - free(in->buffer); + free(in->buffer); free(in); return CURLE_OUT_OF_MEMORY; } @@ -1378,7 +1393,7 @@ static CURLcode https_connecting(struct connectdata *conn, bool *done) } #endif -#if defined(USE_SSLEAY) || defined(USE_GNUTLS) || defined(USE_SCHANNEL) || \ +#if defined(USE_OPENSSL) || defined(USE_GNUTLS) || defined(USE_SCHANNEL) || \ defined(USE_DARWINSSL) || defined(USE_POLARSSL) || defined(USE_NSS) /* This function is for OpenSSL, GnuTLS, darwinssl, schannel and polarssl only. It should be made to query the generic SSL layer instead. */ @@ -1417,7 +1432,7 @@ static int https_getsock(struct connectdata *conn, return GETSOCK_BLANK; } #endif /* USE_SSL */ -#endif /* USE_SSLEAY || USE_GNUTLS || USE_SCHANNEL */ +#endif /* USE_OPENSSL || USE_GNUTLS || USE_SCHANNEL */ /* * Curl_http_done() gets called from Curl_done() after a single HTTP request @@ -1428,19 +1443,26 @@ CURLcode Curl_http_done(struct connectdata *conn, CURLcode status, bool premature) { struct SessionHandle *data = conn->data; - struct HTTP *http =data->req.protop; + struct HTTP *http = data->req.protop; +#ifdef USE_NGHTTP2 + struct http_conn *httpc = &conn->proto.httpc; +#endif Curl_unencode_cleanup(conn); #ifdef USE_SPNEGO if(data->state.proxyneg.state == GSS_AUTHSENT || - data->state.negotiate.state == GSS_AUTHSENT) + data->state.negotiate.state == GSS_AUTHSENT) { + /* add forbid re-use if http-code != 401/407 as a WA only needed for + * 401/407 that signal auth failure (empty) otherwise state will be RECV + * with current code */ + if((data->req.httpcode != 401) && (data->req.httpcode != 407)) + connclose(conn, "Negotiate transfer completed"); Curl_cleanup_negotiate(data); + } #endif /* set the proper values (possibly modified on POST) */ - conn->fread_func = data->set.fread_func; /* restore */ - conn->fread_in = data->set.in; /* restore */ conn->seek_func = data->set.seek_func; /* restore */ conn->seek_client = data->set.seek_client; /* restore */ @@ -1448,13 +1470,27 @@ CURLcode Curl_http_done(struct connectdata *conn, return CURLE_OK; if(http->send_buffer) { - Curl_send_buffer *buff = http->send_buffer; - - free(buff->buffer); - free(buff); + Curl_add_buffer_free(http->send_buffer); http->send_buffer = NULL; /* clear the pointer */ } +#ifdef USE_NGHTTP2 + if(http->header_recvbuf) { + DEBUGF(infof(data, "free header_recvbuf!!\n")); + Curl_add_buffer_free(http->header_recvbuf); + http->header_recvbuf = NULL; /* clear the pointer */ + for(; http->push_headers_used > 0; --http->push_headers_used) { + free(http->push_headers[http->push_headers_used - 1]); + } + free(http->push_headers); + http->push_headers = NULL; + } + if(http->stream_id) { + nghttp2_session_set_stream_user_data(httpc->h2, http->stream_id, 0); + http->stream_id = 0; + } +#endif + if(HTTPREQ_POST_FORM == data->set.httpreq) { data->req.bytecount = http->readbytecount + http->writebytecount; @@ -1468,8 +1504,8 @@ CURLcode Curl_http_done(struct connectdata *conn, else if(HTTPREQ_PUT == data->set.httpreq) data->req.bytecount = http->readbytecount + http->writebytecount; - if(status != CURLE_OK) - return (status); + if(status) + return status; if(!premature && /* this check is pointless when DONE is called before the entire operation is complete */ @@ -1517,10 +1553,11 @@ static CURLcode expect100(struct SessionHandle *data, const char *ptr; data->state.expect100header = FALSE; /* default to false unless it is set to TRUE below */ - if(use_http_1_1plus(data, conn)) { - /* if not doing HTTP 1.0 or disabled explicitly, we add a Expect: - 100-continue to the headers which actually speeds up post operations - (as there is one packet coming back from the web server) */ + if(use_http_1_1plus(data, conn) && + (conn->httpversion != 20)) { + /* if not doing HTTP 1.0 or version 2, or disabled explicitly, we add an + Expect: 100-continue to the headers which actually speeds up post + operations (as there is one packet coming back from the web server) */ ptr = Curl_checkheaders(conn, "Expect:"); if(ptr) { data->state.expect100header = @@ -1529,7 +1566,7 @@ static CURLcode expect100(struct SessionHandle *data, else { result = Curl_add_bufferf(req_buffer, "Expect: 100-continue\r\n"); - if(result == CURLE_OK) + if(!result) data->state.expect100header = TRUE; } } @@ -1659,10 +1696,8 @@ CURLcode Curl_add_timecondition(struct SessionHandle *data, { const struct tm *tm; char *buf = data->state.buffer; - CURLcode result = CURLE_OK; struct tm keeptime; - - result = Curl_gmtime(data->set.timevalue, &keeptime); + CURLcode result = Curl_gmtime(data->set.timevalue, &keeptime); if(result) { failf(data, "Invalid TIMEVALUE"); return result; @@ -1713,8 +1748,8 @@ CURLcode Curl_add_timecondition(struct SessionHandle *data, */ CURLcode Curl_http(struct connectdata *conn, bool *done) { - struct SessionHandle *data=conn->data; - CURLcode result=CURLE_OK; + struct SessionHandle *data = conn->data; + CURLcode result = CURLE_OK; struct HTTP *http; const char *ppath = data->state.path; bool paste_ftp_userpwd = FALSE; @@ -1724,7 +1759,9 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) const char *ptr; const char *request; Curl_HttpReq httpreq = data->set.httpreq; +#if !defined(CURL_DISABLE_COOKIES) char *addcookies = NULL; +#endif curl_off_t included_body = 0; const char *httpstring; Curl_send_buffer *req_buffer; @@ -1738,8 +1775,9 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) if(conn->httpversion < 20) { /* unless the connection is re-used and already http2 */ - switch (conn->negnpn) { - case NPN_HTTP2: + switch(conn->negnpn) { + case CURL_HTTP_VERSION_2_0: + conn->httpversion = 20; /* we know we're on HTTP/2 now */ result = Curl_http2_init(conn); if(result) return result; @@ -1748,11 +1786,11 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) if(result) return result; - result = Curl_http2_switched(conn); + result = Curl_http2_switched(conn, NULL, 0); if(result) return result; break; - case NPN_HTTP1_1: + case CURL_HTTP_VERSION_1_1: /* continue with HTTP/1.1 when explicitly requested */ break; default: @@ -1770,10 +1808,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) http = data->req.protop; if(!data->state.this_is_a_follow) { - /* this is not a followed location, get the original host name */ - if(data->state.first_host) - /* Free to avoid leaking memory on multiple requests*/ - free(data->state.first_host); + /* Free to avoid leaking memory on multiple requests*/ + free(data->state.first_host); data->state.first_host = strdup(conn->host.name); if(!data->state.first_host) @@ -1817,7 +1853,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) it might have been used in the proxy connect, but if we have got a header with the user-agent string specified, we erase the previously made string here. */ - if(Curl_checkheaders(conn, "User-Agent:") && conn->allocptr.uagent) { + if(Curl_checkheaders(conn, "User-Agent:")) { free(conn->allocptr.uagent); conn->allocptr.uagent=NULL; } @@ -1846,8 +1882,10 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) else conn->allocptr.ref = NULL; +#if !defined(CURL_DISABLE_COOKIES) if(data->set.str[STRING_COOKIE] && !Curl_checkheaders(conn, "Cookie:")) addcookies = data->set.str[STRING_COOKIE]; +#endif if(!Curl_checkheaders(conn, "Accept-Encoding:") && data->set.str[STRING_ENCODING]) { @@ -1958,7 +1996,14 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) } #endif - conn->allocptr.host = NULL; + if(strcmp("Host:", ptr)) { + conn->allocptr.host = aprintf("%s\r\n", ptr); + if(!conn->allocptr.host) + return CURLE_OUT_OF_MEMORY; + } + else + /* when clearing the header */ + conn->allocptr.host = NULL; } else { /* When building Host: headers, we must put the host name within @@ -2153,8 +2198,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) if(((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD)) && !Curl_checkheaders(conn, "Range:")) { /* if a line like this was already allocated, free the previous one */ - if(conn->allocptr.rangeline) - free(conn->allocptr.rangeline); + free(conn->allocptr.rangeline); conn->allocptr.rangeline = aprintf("Range: bytes=%s\r\n", data->state.range); } @@ -2162,8 +2206,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) !Curl_checkheaders(conn, "Content-Range:")) { /* if a line like this was already allocated, free the previous one */ - if(conn->allocptr.rangeline) - free(conn->allocptr.rangeline); + free(conn->allocptr.rangeline); if(data->set.set_resume_from < 0) { /* Upload resume was asked for, but we don't know the size of the @@ -2227,11 +2270,11 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) Curl_add_bufferf(req_buffer, "%s" /* ftp typecode (;type=x) */ " HTTP/%s\r\n" /* HTTP version */ + "%s" /* host */ "%s" /* proxyuserpwd */ "%s" /* userpwd */ "%s" /* range */ "%s" /* user agent */ - "%s" /* host */ "%s" /* accept */ "%s" /* TE: */ "%s" /* accept-encoding */ @@ -2241,6 +2284,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) ftp_typecode, httpstring, + (conn->allocptr.host?conn->allocptr.host:""), conn->allocptr.proxyuserpwd? conn->allocptr.proxyuserpwd:"", conn->allocptr.userpwd?conn->allocptr.userpwd:"", @@ -2250,7 +2294,6 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) *data->set.str[STRING_USERAGENT] && conn->allocptr.uagent)? conn->allocptr.uagent:"", - (conn->allocptr.host?conn->allocptr.host:""), http->p_accept?http->p_accept:"", conn->allocptr.te?conn->allocptr.te:"", (data->set.str[STRING_ENCODING] && @@ -2266,18 +2309,26 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) te ); + /* clear userpwd to avoid re-using credentials from re-used connections */ + Curl_safefree(conn->allocptr.userpwd); + /* - * Free userpwd now --- cannot reuse this for Negotiate and possibly NTLM - * with basic and digest, it will be freed anyway by the next request + * Free proxyuserpwd for Negotiate/NTLM. Cannot reuse as it is associated + * with the connection and shouldn't be repeated over it either. */ - - Curl_safefree (conn->allocptr.userpwd); - conn->allocptr.userpwd = NULL; + switch (data->state.authproxy.picked) { + case CURLAUTH_NEGOTIATE: + case CURLAUTH_NTLM: + case CURLAUTH_NTLM_WB: + Curl_safefree(conn->allocptr.proxyuserpwd); + break; + } if(result) return result; if(!(conn->handler->flags&PROTOPT_SSL) && + conn->httpversion != 20 && (data->set.httpversion == CURL_HTTP_VERSION_2_0)) { /* append HTTP2 upgrade magic stuff to the HTTP request if it isn't done over SSL */ @@ -2322,17 +2373,16 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) } Curl_cookie_freelist(store, FALSE); /* free the cookie list */ } - if(addcookies && (CURLE_OK == result)) { + if(addcookies && !result) { if(!count) result = Curl_add_bufferf(req_buffer, "Cookie: "); - if(CURLE_OK == result) { - result = Curl_add_bufferf(req_buffer, "%s%s", - count?"; ":"", + if(!result) { + result = Curl_add_bufferf(req_buffer, "%s%s", count?"; ":"", addcookies); count++; } } - if(count && (CURLE_OK == result)) + if(count && !result) result = Curl_add_buffer(req_buffer, "\r\n", 2); if(result) @@ -2384,14 +2434,14 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) /* 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 conn->fread_func pointer itself will be changed for the + 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 = conn->fread_func; + http->form.fread_func = data->set.fread_func; /* Set the read function to read from the generated form data */ - conn->fread_func = (curl_read_callback)Curl_FormReader; - conn->fread_in = &http->form; + data->set.fread_func = (curl_read_callback)Curl_FormReader; + data->set.in = &http->form; http->sending = HTTPSEND_BODY; @@ -2511,8 +2561,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) postsize = 0; else { /* figure out the size of the postfields */ - postsize = (data->set.postfieldsize != -1)? - data->set.postfieldsize: + postsize = (data->state.infilesize != -1)? + data->state.infilesize: (data->set.postfields? (curl_off_t)strlen(data->set.postfields):-1); } @@ -2584,17 +2634,16 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) if(postsize) { /* Append the POST data chunky-style */ result = Curl_add_bufferf(req_buffer, "%x\r\n", (int)postsize); - if(CURLE_OK == result) { + if(!result) { result = Curl_add_buffer(req_buffer, data->set.postfields, (size_t)postsize); - if(CURLE_OK == result) - result = Curl_add_buffer(req_buffer, "\r\n", 2); + if(!result) + result = Curl_add_buffer(req_buffer, "\r\n", 2); included_body = postsize + 2; } } - if(CURLE_OK == result) - result = Curl_add_buffer(req_buffer, - "\x30\x0d\x0a\x0d\x0a", 5); + if(!result) + result = Curl_add_buffer(req_buffer, "\x30\x0d\x0a\x0d\x0a", 5); /* 0 CR LF CR LF */ included_body += 5; } @@ -2610,8 +2659,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) http->sending = HTTPSEND_BODY; - conn->fread_func = (curl_read_callback)readmoredata; - conn->fread_in = (void *)conn; + data->set.fread_func = (curl_read_callback)readmoredata; + data->set.in = (void *)conn; /* set the upload size to the progress meter */ Curl_pgrsSetUploadSize(data, http->postsize); @@ -2636,7 +2685,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) return result; } - else if(data->set.postfieldsize) { + else if(data->state.infilesize) { /* set the upload size to the progress meter */ Curl_pgrsSetUploadSize(data, postsize?postsize:-1); @@ -2997,10 +3046,12 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, infof(data, "Received 101\n"); k->upgr101 = UPGR101_RECEIVED; - /* switch to http2 now */ - result = Curl_http2_switched(conn); + /* switch to http2 now. The bytes after response headers + are also processed here, otherwise they are lost. */ + result = Curl_http2_switched(conn, k->str, *nread); if(result) return result; + *nread = 0; } break; default: @@ -3025,6 +3076,19 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, } } + /* At this point we have some idea about the fate of the connection. + If we are closing the connection it may result auth failure. */ +#if defined(USE_NTLM) + if(conn->bits.close && + (((data->req.httpcode == 401) && + (conn->ntlm.state == NTLMSTATE_TYPE2)) || + ((data->req.httpcode == 407) && + (conn->proxyntlm.state == NTLMSTATE_TYPE2)))) { + infof(data, "Connection closure while negotiating auth (HTTP 1.0?)\n"); + data->state.authproblem = TRUE; + } +#endif + /* * When all the headers have been parsed, see if we should give * up and return an error. @@ -3203,13 +3267,26 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, #endif /* CURL_DOES_CONVERSIONS */ if(conn->handler->protocol & PROTO_FAMILY_HTTP) { + /* + * https://tools.ietf.org/html/rfc7230#section-3.1.2 + * + * The reponse code is always a three-digit number in HTTP as the spec + * says. We try to allow any number here, but we cannot make + * guarantees on future behaviors since it isn't within the protocol. + */ nc = sscanf(HEADER1, - " HTTP/%d.%d %3d", + " HTTP/%d.%d %d", &httpversion_major, &conn->httpversion, &k->httpcode); if(nc==3) { conn->httpversion += 10 * httpversion_major; + + if(k->upgr101 == UPGR101_RECEIVED) { + /* supposedly upgraded to http2 now */ + if(conn->httpversion != 20) + infof(data, "Lying server, not serving HTTP/2\n"); + } } else { /* this is the real world, not a Nirvana @@ -3287,20 +3364,25 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, infof(data, "HTTP 1.0, assume close after body\n"); connclose(conn, "HTTP/1.0 close after body"); } + else if(conn->httpversion == 20 || + (k->upgr101 == UPGR101_REQUESTED && k->httpcode == 101)) { + DEBUGF(infof(data, "HTTP/2 found, allow multiplexing\n")); + + /* HTTP/2 cannot blacklist multiplexing since it is a core + functionality of the protocol */ + conn->bundle->multiuse = BUNDLE_MULTIPLEX; + } else if(conn->httpversion >= 11 && !conn->bits.close) { - struct connectbundle *cb_ptr; - /* If HTTP version is >= 1.1 and connection is persistent server supports pipelining. */ DEBUGF(infof(data, "HTTP 1.1 or later with persistent connection, " "pipelining supported\n")); /* Activate pipelining if needed */ - cb_ptr = conn->bundle; - if(cb_ptr) { + if(conn->bundle) { if(!Curl_pipeline_site_blacklisted(data, conn)) - cb_ptr->server_supports_pipelining = TRUE; + conn->bundle->multiuse = BUNDLE_PIPELINING; } } @@ -3379,14 +3461,17 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, } } else if(checkprefix("Server:", k->p)) { - char *server_name = Curl_copy_header_value(k->p); - - /* Turn off pipelining if the server version is blacklisted */ - if(conn->bundle && conn->bundle->server_supports_pipelining) { - if(Curl_pipeline_server_blacklisted(data, server_name)) - conn->bundle->server_supports_pipelining = FALSE; + if(conn->httpversion < 20) { + /* only do this for non-h2 servers */ + char *server_name = Curl_copy_header_value(k->p); + + /* Turn off pipelining if the server version is blacklisted */ + if(conn->bundle && (conn->bundle->multiuse == BUNDLE_PIPELINING)) { + if(Curl_pipeline_server_blacklisted(data, server_name)) + conn->bundle->multiuse = BUNDLE_NO_MULTIUSE; + } + free(server_name); } - Curl_safefree(server_name); } else if((conn->httpversion == 10) && conn->bits.httpproxy && @@ -3483,14 +3568,6 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, k->auto_decoding = GZIP; start += 6; } - else if(checkprefix("compress", start)) { - k->auto_decoding = COMPRESS; - start += 8; - } - else if(checkprefix("x-compress", start)) { - k->auto_decoding = COMPRESS; - start += 10; - } else /* unknown! */ break; @@ -3523,9 +3600,6 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, else if(checkprefix("gzip", start) || checkprefix("x-gzip", start)) k->auto_decoding = GZIP; - else if(checkprefix("compress", start) - || checkprefix("x-compress", start)) - k->auto_decoding = COMPRESS; } else if(checkprefix("Content-Range:", k->p)) { /* Content-Range: bytes [num]- @@ -3591,7 +3665,7 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, result = Curl_http_input_auth(conn, proxy, auth); - Curl_safefree(auth); + free(auth); if(result) return result; diff --git a/Utilities/cmcurl/lib/http.h b/Utilities/cmcurl/lib/http.h index 907755a..fe4f39b 100644 --- a/Utilities/cmcurl/lib/http.h +++ b/Utilities/cmcurl/lib/http.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -60,6 +60,7 @@ struct Curl_send_buffer { typedef struct Curl_send_buffer Curl_send_buffer; Curl_send_buffer *Curl_add_buffer_init(void); +void Curl_add_buffer_free(Curl_send_buffer *buff); CURLcode Curl_add_bufferf(Curl_send_buffer *in, const char *fmt, ...); CURLcode Curl_add_buffer(Curl_send_buffer *in, const void *inptr, size_t size); CURLcode Curl_add_buffer_send(Curl_send_buffer *in, @@ -152,42 +153,69 @@ struct HTTP { void *send_buffer; /* used if the request couldn't be sent in one chunk, points to an allocated send_buffer struct */ + +#ifdef USE_NGHTTP2 + /*********** for HTTP/2 we store stream-local data here *************/ + int32_t stream_id; /* stream we are interested in */ + + bool bodystarted; + /* We store non-final and final response headers here, per-stream */ + Curl_send_buffer *header_recvbuf; + size_t nread_header_recvbuf; /* number of bytes in header_recvbuf fed into + upper layer */ + int status_code; /* HTTP status code */ + const uint8_t *pausedata; /* pointer to data received in on_data_chunk */ + size_t pauselen; /* the number of bytes left in data */ + bool closed; /* TRUE on HTTP2 stream close */ + uint32_t error_code; /* HTTP/2 error code */ + + char *mem; /* points to a buffer in memory to store received data */ + size_t len; /* size of the buffer 'mem' points to */ + size_t memlen; /* size of data copied to mem */ + + const uint8_t *upload_mem; /* points to a buffer to read from */ + size_t upload_len; /* size of the buffer 'upload_mem' points to */ + curl_off_t upload_left; /* number of bytes left to upload */ + + char **push_headers; /* allocated array */ + size_t push_headers_used; /* number of entries filled in */ + size_t push_headers_alloc; /* number of entries allocated */ +#endif }; typedef int (*sending)(void); /* Curl_send */ typedef int (*recving)(void); /* Curl_recv */ +#ifdef USE_NGHTTP2 +/* h2 settings for this connection */ +struct h2settings { + uint32_t max_concurrent_streams; + bool enable_push; +}; +#endif + + struct http_conn { #ifdef USE_NGHTTP2 #define H2_BINSETTINGS_LEN 80 nghttp2_session *h2; uint8_t binsettings[H2_BINSETTINGS_LEN]; size_t binlen; /* length of the binsettings data */ - char *mem; /* points to a buffer in memory to store */ - size_t len; /* size of the buffer 'mem' points to */ - bool bodystarted; sending send_underlying; /* underlying send Curl_send callback */ recving recv_underlying; /* underlying recv Curl_recv callback */ - bool closed; /* TRUE on HTTP2 stream close */ - Curl_send_buffer *header_recvbuf; /* store response headers. We - store non-final and final - response headers into it. */ - size_t nread_header_recvbuf; /* number of bytes in header_recvbuf - fed into upper layer */ - int32_t stream_id; /* stream we are interested in */ - const uint8_t *data; /* pointer to data chunk, received in - on_data_chunk */ - size_t datalen; /* the number of bytes left in data */ char *inbuf; /* buffer to receive data from underlying socket */ + size_t inbuflen; /* number of bytes filled in inbuf */ + size_t nread_inbuf; /* number of bytes read from in inbuf */ /* We need separate buffer for transmission and reception because we may call nghttp2_session_send() after the nghttp2_session_mem_recv() but mem buffer is still not full. In this case, we wrongly sends the content of mem buffer if we share them for both cases. */ - const uint8_t *upload_mem; /* points to a buffer to read from */ - size_t upload_len; /* size of the buffer 'upload_mem' points to */ - size_t upload_left; /* number of bytes left to upload */ - int status_code; /* HTTP status code */ + int32_t pause_stream_id; /* stream ID which paused + nghttp2_session_mem_recv */ + + /* this is a hash of all individual streams (SessionHandle structs) */ + struct h2settings settings; #else int unused; /* prevent a compiler warning */ #endif diff --git a/Utilities/cmcurl/lib/http2.c b/Utilities/cmcurl/lib/http2.c index 604514d..0024add 100644 --- a/Utilities/cmcurl/lib/http2.c +++ b/Utilities/cmcurl/lib/http2.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -23,22 +23,24 @@ #include "curl_setup.h" #ifdef USE_NGHTTP2 -#define _MPRINTF_REPLACE -#include <curl/mprintf.h> - +#include "curl_printf.h" #include <nghttp2/nghttp2.h> #include "urldata.h" #include "http2.h" #include "http.h" #include "sendf.h" #include "curl_base64.h" -#include "curl_memory.h" #include "rawstr.h" #include "multiif.h" +#include "conncache.h" +#include "url.h" -/* include memdebug.h last */ +/* The last #include files should be: */ +#include "curl_memory.h" #include "memdebug.h" +#define MIN(x,y) ((x)<(y)?(x):(y)) + #if (NGHTTP2_VERSION_NUM < 0x000600) #error too old nghttp2 version, upgrade! #endif @@ -50,7 +52,7 @@ static int http2_perform_getsock(const struct connectdata *conn, sockets */ int numsocks) { - const struct http_conn *httpc = &conn->proto.httpc; + const struct http_conn *c = &conn->proto.httpc; int bitmap = GETSOCK_BLANK; (void)numsocks; @@ -58,10 +60,10 @@ static int http2_perform_getsock(const struct connectdata *conn, because of renegotiation. */ sock[0] = conn->sock[FIRSTSOCKET]; - if(nghttp2_session_want_read(httpc->h2)) + if(nghttp2_session_want_read(c->h2)) bitmap |= GETSOCK_READSOCK(FIRSTSOCKET); - if(nghttp2_session_want_write(httpc->h2)) + if(nghttp2_session_want_write(c->h2)) bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET); return bitmap; @@ -78,23 +80,54 @@ static int http2_getsock(struct connectdata *conn, static CURLcode http2_disconnect(struct connectdata *conn, bool dead_connection) { - struct http_conn *httpc = &conn->proto.httpc; + struct HTTP *http = conn->data->req.protop; + struct http_conn *c = &conn->proto.httpc; (void)dead_connection; - infof(conn->data, "HTTP/2 DISCONNECT starts now\n"); - - nghttp2_session_del(httpc->h2); + DEBUGF(infof(conn->data, "HTTP/2 DISCONNECT starts now\n")); - Curl_safefree(httpc->header_recvbuf->buffer); - Curl_safefree(httpc->header_recvbuf); + nghttp2_session_del(c->h2); + Curl_safefree(c->inbuf); - Curl_safefree(httpc->inbuf); + if(http) { + Curl_add_buffer_free(http->header_recvbuf); + http->header_recvbuf = NULL; /* clear the pointer */ + for(; http->push_headers_used > 0; --http->push_headers_used) { + free(http->push_headers[http->push_headers_used - 1]); + } + free(http->push_headers); + http->push_headers = NULL; + } - infof(conn->data, "HTTP/2 DISCONNECT done\n"); + DEBUGF(infof(conn->data, "HTTP/2 DISCONNECT done\n")); return CURLE_OK; } +/* called from Curl_http_setup_conn */ +void Curl_http2_setup_req(struct SessionHandle *data) +{ + struct HTTP *http = data->req.protop; + + http->nread_header_recvbuf = 0; + http->bodystarted = FALSE; + http->status_code = -1; + http->pausedata = NULL; + http->pauselen = 0; + http->error_code = NGHTTP2_NO_ERROR; + http->closed = FALSE; + http->mem = data->state.buffer; + http->len = BUFSIZE; + http->memlen = 0; +} + +/* called from Curl_http_setup_conn */ +void Curl_http2_setup_conn(struct connectdata *conn) +{ + conn->proto.httpc.settings.max_concurrent_streams = + DEFAULT_MAX_CONCURRENT_STREAMS; +} + /* * HTTP2 handler interface. This isn't added to the general list of protocols * but will be used at run-time when the protocol is dynamically switched from @@ -104,7 +137,7 @@ const struct Curl_handler Curl_handler_http2 = { "HTTP2", /* scheme */ ZERO_NULL, /* setup_connection */ Curl_http, /* do_it */ - ZERO_NULL, /* done */ + Curl_http_done, /* done */ ZERO_NULL, /* do_more */ ZERO_NULL, /* connect_it */ ZERO_NULL, /* connecting */ @@ -124,7 +157,7 @@ const struct Curl_handler Curl_handler_http2_ssl = { "HTTP2", /* scheme */ ZERO_NULL, /* setup_connection */ Curl_http, /* do_it */ - ZERO_NULL, /* done */ + Curl_http_done, /* done */ ZERO_NULL, /* do_more */ ZERO_NULL, /* connect_it */ ZERO_NULL, /* connecting */ @@ -160,17 +193,17 @@ static ssize_t send_callback(nghttp2_session *h2, void *userp) { struct connectdata *conn = (struct connectdata *)userp; - struct http_conn *httpc = &conn->proto.httpc; + struct http_conn *c = &conn->proto.httpc; ssize_t written; - CURLcode rc; + CURLcode result = CURLE_OK; + (void)h2; (void)flags; - rc = 0; - written = ((Curl_send*)httpc->send_underlying)(conn, FIRSTSOCKET, - data, length, &rc); + written = ((Curl_send*)c->send_underlying)(conn, FIRSTSOCKET, + data, length, &result); - if(rc == CURLE_AGAIN) { + if(result == CURLE_AGAIN) { return NGHTTP2_ERR_WOULDBLOCK; } @@ -185,25 +218,205 @@ static ssize_t send_callback(nghttp2_session *h2, return written; } + +/* We pass a pointer to this struct in the push callback, but the contents of + the struct are hidden from the user. */ +struct curl_pushheaders { + struct SessionHandle *data; + const nghttp2_push_promise *frame; +}; + +/* + * push header access function. Only to be used from within the push callback + */ +char *curl_pushheader_bynum(struct curl_pushheaders *h, size_t num) +{ + /* Verify that we got a good easy handle in the push header struct, mostly to + detect rubbish input fast(er). */ + if(!h || !GOOD_EASY_HANDLE(h->data)) + return NULL; + else { + struct HTTP *stream = h->data->req.protop; + if(num < stream->push_headers_used) + return stream->push_headers[num]; + } + return NULL; +} + +/* + * push header access function. Only to be used from within the push callback + */ +char *curl_pushheader_byname(struct curl_pushheaders *h, const char *header) +{ + /* Verify that we got a good easy handle in the push header struct, + mostly to detect rubbish input fast(er). Also empty header name + is just a rubbish too. We have to allow ":" at the beginning of + the header, but header == ":" must be rejected. If we have ':' in + the middle of header, it could be matched in middle of the value, + this is because we do prefix match.*/ + if(!h || !GOOD_EASY_HANDLE(h->data) || !header || !header[0] || + Curl_raw_equal(header, ":") || strchr(header + 1, ':')) + return NULL; + else { + struct HTTP *stream = h->data->req.protop; + size_t len = strlen(header); + size_t i; + for(i=0; i<stream->push_headers_used; i++) { + if(!strncmp(header, stream->push_headers[i], len)) { + /* sub-match, make sure that it us followed by a colon */ + if(stream->push_headers[i][len] != ':') + continue; + return &stream->push_headers[i][len+1]; + } + } + } + return NULL; +} + +static CURL *duphandle(struct SessionHandle *data) +{ + struct SessionHandle *second = curl_easy_duphandle(data); + if(second) { + /* setup the request struct */ + struct HTTP *http = calloc(1, sizeof(struct HTTP)); + if(!http) { + (void)Curl_close(second); + second = NULL; + } + else { + second->req.protop = http; + http->header_recvbuf = Curl_add_buffer_init(); + if(!http->header_recvbuf) { + free(http); + (void)Curl_close(second); + second = NULL; + } + else + Curl_http2_setup_req(second); + } + } + return second; +} + + +static int push_promise(struct SessionHandle *data, + struct connectdata *conn, + const nghttp2_push_promise *frame) +{ + int rv; + DEBUGF(infof(data, "PUSH_PROMISE received, stream %u!\n", + frame->promised_stream_id)); + if(data->multi->push_cb) { + struct HTTP *stream; + struct curl_pushheaders heads; + CURLMcode rc; + struct http_conn *httpc; + size_t i; + /* clone the parent */ + CURL *newhandle = duphandle(data); + if(!newhandle) { + infof(data, "failed to duplicate handle\n"); + rv = 1; /* FAIL HARD */ + goto fail; + } + + heads.data = data; + heads.frame = frame; + /* ask the application */ + DEBUGF(infof(data, "Got PUSH_PROMISE, ask application!\n")); + + stream = data->req.protop; + if(!stream) { + failf(data, "Internal NULL stream!\n"); + rv = 1; + goto fail; + } + + rv = data->multi->push_cb(data, newhandle, + stream->push_headers_used, &heads, + data->multi->push_userp); + + /* free the headers again */ + for(i=0; i<stream->push_headers_used; i++) + free(stream->push_headers[i]); + free(stream->push_headers); + stream->push_headers = NULL; + + if(rv) { + /* denied, kill off the new handle again */ + (void)Curl_close(newhandle); + goto fail; + } + + /* approved, add to the multi handle and immediately switch to PERFORM + state with the given connection !*/ + rc = Curl_multi_add_perform(data->multi, newhandle, conn); + if(rc) { + infof(data, "failed to add handle to multi\n"); + Curl_close(newhandle); + rv = 1; + goto fail; + } + + httpc = &conn->proto.httpc; + nghttp2_session_set_stream_user_data(httpc->h2, + frame->promised_stream_id, newhandle); + } + else { + DEBUGF(infof(data, "Got PUSH_PROMISE, ignore it!\n")); + rv = 1; + } + fail: + return rv; +} + static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame, void *userp) { - struct connectdata *conn = (struct connectdata *)userp; - struct http_conn *c = &conn->proto.httpc; + struct connectdata *conn = NULL; + struct http_conn *httpc = NULL; + struct SessionHandle *data_s = NULL; + struct HTTP *stream = NULL; + static int lastStream = -1; int rv; size_t left, ncopy; + int32_t stream_id = frame->hd.stream_id; - (void)session; - (void)frame; - infof(conn->data, "on_frame_recv() was called with header %x\n", - frame->hd.type); + (void)userp; + + if(!stream_id) { + /* stream ID zero is for connection-oriented stuff */ + return 0; + } + data_s = nghttp2_session_get_stream_user_data(session, + frame->hd.stream_id); + if(lastStream != frame->hd.stream_id) { + lastStream = frame->hd.stream_id; + } + if(!data_s) { + DEBUGF(infof(conn->data, + "No SessionHandle associated with stream: %x\n", + stream_id)); + return 0; + } + + stream = data_s->req.protop; + if(!stream) + return NGHTTP2_ERR_CALLBACK_FAILURE; + + DEBUGF(infof(data_s, "on_frame_recv() header %x stream %x\n", + frame->hd.type, stream_id)); + + conn = data_s->easy_conn; + assert(conn); + assert(conn->data == data_s); + httpc = &conn->proto.httpc; switch(frame->hd.type) { case NGHTTP2_DATA: - /* If body started, then receiving DATA is illegal. */ - if(!c->bodystarted) { + /* If body started on this stream, then receiving DATA is illegal. */ + if(!stream->bodystarted) { rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE, - frame->hd.stream_id, - NGHTTP2_PROTOCOL_ERROR); + stream_id, NGHTTP2_PROTOCOL_ERROR); if(nghttp2_is_fatal(rv)) { return NGHTTP2_ERR_CALLBACK_FAILURE; @@ -214,74 +427,96 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame, if(frame->headers.cat == NGHTTP2_HCAT_REQUEST) break; - if(c->bodystarted) { - /* Only valid HEADERS after body started is trailer header, - which is not fully supported in this code. If HEADERS is not - trailer, then it is a PROTOCOL_ERROR. */ - if((frame->hd.flags & NGHTTP2_FLAG_END_STREAM) == 0) { - rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE, - frame->hd.stream_id, - NGHTTP2_PROTOCOL_ERROR); - - if(nghttp2_is_fatal(rv)) { - return NGHTTP2_ERR_CALLBACK_FAILURE; - } - } + if(stream->bodystarted) { + /* Only valid HEADERS after body started is trailer HEADERS. We + ignores trailer HEADERS for now. nghttp2 guarantees that it + has END_STREAM flag set. */ break; } - if(c->status_code == -1) { - /* No :status header field means PROTOCOL_ERROR. */ - rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE, - frame->hd.stream_id, - NGHTTP2_PROTOCOL_ERROR); - - if(nghttp2_is_fatal(rv)) { - return NGHTTP2_ERR_CALLBACK_FAILURE; - } - - break; - } + /* nghttp2 guarantees that :status is received, and we store it to + stream->status_code */ + DEBUGASSERT(stream->status_code != -1); /* Only final status code signals the end of header */ - if(c->status_code / 100 != 1) { - c->bodystarted = TRUE; + if(stream->status_code / 100 != 1) { + stream->bodystarted = TRUE; + stream->status_code = -1; } - c->status_code = -1; + Curl_add_buffer(stream->header_recvbuf, "\r\n", 2); - Curl_add_buffer(c->header_recvbuf, "\r\n", 2); + left = stream->header_recvbuf->size_used - stream->nread_header_recvbuf; + ncopy = MIN(stream->len, left); + + memcpy(&stream->mem[stream->memlen], + stream->header_recvbuf->buffer + stream->nread_header_recvbuf, + ncopy); + stream->nread_header_recvbuf += ncopy; - left = c->header_recvbuf->size_used - c->nread_header_recvbuf; - ncopy = c->len < left ? c->len : left; + DEBUGF(infof(data_s, "Store %zu bytes headers from stream %u at %p\n", + ncopy, stream_id, stream->mem)); - memcpy(c->mem, c->header_recvbuf->buffer + c->nread_header_recvbuf, ncopy); - c->nread_header_recvbuf += ncopy; + stream->len -= ncopy; + stream->memlen += ncopy; - c->mem += ncopy; - c->len -= ncopy; + data_s->state.drain++; + Curl_expire(data_s, 1); break; case NGHTTP2_PUSH_PROMISE: - rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE, - frame->push_promise.promised_stream_id, - NGHTTP2_CANCEL); - if(nghttp2_is_fatal(rv)) { - return rv; + rv = push_promise(data_s, conn, &frame->push_promise); + if(rv) { /* deny! */ + rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE, + frame->push_promise.promised_stream_id, + NGHTTP2_CANCEL); + if(nghttp2_is_fatal(rv)) { + return rv; + } } break; + case NGHTTP2_SETTINGS: + { + uint32_t max_conn = httpc->settings.max_concurrent_streams; + DEBUGF(infof(conn->data, "Got SETTINGS for stream %u!\n", stream_id)); + httpc->settings.max_concurrent_streams = + nghttp2_session_get_remote_settings( + session, NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS); + httpc->settings.enable_push = + nghttp2_session_get_remote_settings( + session, NGHTTP2_SETTINGS_ENABLE_PUSH); + DEBUGF(infof(conn->data, "MAX_CONCURRENT_STREAMS == %d\n", + httpc->settings.max_concurrent_streams)); + DEBUGF(infof(conn->data, "ENABLE_PUSH == %s\n", + httpc->settings.enable_push?"TRUE":"false")); + if(max_conn != httpc->settings.max_concurrent_streams) { + /* only signal change if the value actually changed */ + infof(conn->data, + "Connection state changed (MAX_CONCURRENT_STREAMS updated)!\n"); + Curl_multi_connchanged(conn->data->multi); + } + } + break; + default: + DEBUGF(infof(conn->data, "Got frame type %x for stream %u!\n", + frame->hd.type, stream_id)); + break; } return 0; } static int on_invalid_frame_recv(nghttp2_session *session, const nghttp2_frame *frame, - uint32_t error_code, void *userp) + int lib_error_code, void *userp) { - struct connectdata *conn = (struct connectdata *)userp; - (void)session; - (void)frame; - infof(conn->data, "on_invalid_frame_recv() was called, error_code = %d\n", - error_code); + struct SessionHandle *data_s = NULL; + (void)userp; + + data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id); + if(data_s) { + DEBUGF(infof(data_s, + "on_invalid_frame_recv() was called, error=%d:%s\n", + lib_error_code, nghttp2_strerror(lib_error_code))); + } return 0; } @@ -289,30 +524,50 @@ static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags, int32_t stream_id, const uint8_t *data, size_t len, void *userp) { - struct connectdata *conn = (struct connectdata *)userp; - struct http_conn *c = &conn->proto.httpc; + struct HTTP *stream; + struct SessionHandle *data_s; size_t nread; (void)session; (void)flags; (void)data; - infof(conn->data, "on_data_chunk_recv() " - "len = %u, stream = %x\n", len, stream_id); + (void)userp; - if(stream_id != c->stream_id) { - return 0; - } + DEBUGASSERT(stream_id); /* should never be a zero stream ID here */ - nread = c->len < len ? c->len : len; - memcpy(c->mem, data, nread); + /* get the stream from the hash based on Stream ID */ + data_s = nghttp2_session_get_stream_user_data(session, stream_id); + if(!data_s) + /* Receiving a Stream ID not in the hash should not happen, this is an + internal error more than anything else! */ + return NGHTTP2_ERR_CALLBACK_FAILURE; + + stream = data_s->req.protop; + if(!stream) + return NGHTTP2_ERR_CALLBACK_FAILURE; - c->mem += nread; - c->len -= nread; + nread = MIN(stream->len, len); + memcpy(&stream->mem[stream->memlen], data, nread); - infof(conn->data, "%zu data written\n", nread); + stream->len -= nread; + stream->memlen += nread; + + data_s->state.drain++; + Curl_expire(data_s, 1); /* TODO: fix so that this can be set to 0 for + immediately? */ + + DEBUGF(infof(data_s, "%zu data received for stream %u " + "(%zu left in buffer %p, total %zu)\n", + nread, stream_id, + stream->len, stream->mem, + stream->memlen)); if(nread < len) { - c->data = data + nread; - c->datalen = len - nread; + stream->pausedata = data + nread; + stream->pauselen = len - nread; + DEBUGF(infof(data_s, "NGHTTP2_ERR_PAUSE - %zu bytes out of buffer" + ", stream %u\n", + len - nread, stream_id)); + data_s->easy_conn->proto.httpc.pause_stream_id = stream_id; return NGHTTP2_ERR_PAUSE; } return 0; @@ -322,59 +577,89 @@ static int before_frame_send(nghttp2_session *session, const nghttp2_frame *frame, void *userp) { - struct connectdata *conn = (struct connectdata *)userp; - (void)session; - (void)frame; - infof(conn->data, "before_frame_send() was called\n"); + struct SessionHandle *data_s; + (void)userp; + + data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id); + if(data_s) { + DEBUGF(infof(data_s, "before_frame_send() was called\n")); + } + return 0; } static int on_frame_send(nghttp2_session *session, const nghttp2_frame *frame, void *userp) { - struct connectdata *conn = (struct connectdata *)userp; - (void)session; - (void)frame; - infof(conn->data, "on_frame_send() was called\n"); + struct SessionHandle *data_s; + (void)userp; + + data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id); + if(data_s) { + DEBUGF(infof(data_s, "on_frame_send() was called, length = %zd\n", + frame->hd.length)); + } return 0; } static int on_frame_not_send(nghttp2_session *session, const nghttp2_frame *frame, int lib_error_code, void *userp) { - struct connectdata *conn = (struct connectdata *)userp; - (void)session; - (void)frame; - infof(conn->data, "on_frame_not_send() was called, lib_error_code = %d\n", - lib_error_code); + struct SessionHandle *data_s; + (void)userp; + + data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id); + if(data_s) { + DEBUGF(infof(data_s, + "on_frame_not_send() was called, lib_error_code = %d\n", + lib_error_code)); + } return 0; } static int on_stream_close(nghttp2_session *session, int32_t stream_id, uint32_t error_code, void *userp) { - struct connectdata *conn = (struct connectdata *)userp; - struct http_conn *c = &conn->proto.httpc; + struct SessionHandle *data_s; + struct HTTP *stream; (void)session; (void)stream_id; - infof(conn->data, "on_stream_close() was called, error_code = %d\n", - error_code); - - if(stream_id != c->stream_id) { - return 0; - } + (void)userp; + + if(stream_id) { + /* get the stream from the hash based on Stream ID, stream ID zero is for + connection-oriented stuff */ + data_s = nghttp2_session_get_stream_user_data(session, stream_id); + if(!data_s) { + /* We could get stream ID not in the hash. For example, if we + decided to reject stream (e.g., PUSH_PROMISE). */ + return 0; + } + DEBUGF(infof(data_s, "on_stream_close(), error_code = %d, stream %u\n", + error_code, stream_id)); + stream = data_s->req.protop; + if(!stream) + return NGHTTP2_ERR_CALLBACK_FAILURE; - c->closed = TRUE; + stream->error_code = error_code; + stream->closed = TRUE; + /* remove the entry from the hash as the stream is now gone */ + nghttp2_session_set_stream_user_data(session, stream_id, 0); + DEBUGF(infof(data_s, "Removed stream %u hash!\n", stream_id)); + } return 0; } static int on_begin_headers(nghttp2_session *session, const nghttp2_frame *frame, void *userp) { - struct connectdata *conn = (struct connectdata *)userp; - (void)session; - (void)frame; - infof(conn->data, "on_begin_headers() was called\n"); + struct SessionHandle *data_s = NULL; + (void)userp; + + data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id); + if(data_s) { + DEBUGF(infof(data_s, "on_begin_headers() was called\n")); + } return 0; } @@ -405,8 +690,6 @@ static int decode_status_code(const uint8_t *value, size_t len) return res; } -static const char STATUS[] = ":status"; - /* frame->hd.type is either NGHTTP2_HEADERS or NGHTTP2_PUSH_PROMISE */ static int on_header(nghttp2_session *session, const nghttp2_frame *frame, const uint8_t *name, size_t namelen, @@ -414,93 +697,94 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame, uint8_t flags, void *userp) { - struct connectdata *conn = (struct connectdata *)userp; - struct http_conn *c = &conn->proto.httpc; - int rv; - int goodname; - int goodheader; + struct HTTP *stream; + struct SessionHandle *data_s; + int32_t stream_id = frame->hd.stream_id; - (void)session; - (void)frame; (void)flags; + (void)userp; - if(frame->hd.stream_id != c->stream_id) { - return 0; + DEBUGASSERT(stream_id); /* should never be a zero stream ID here */ + + /* get the stream from the hash based on Stream ID */ + data_s = nghttp2_session_get_stream_user_data(session, stream_id); + if(!data_s) + /* Receiving a Stream ID not in the hash should not happen, this is an + internal error more than anything else! */ + return NGHTTP2_ERR_CALLBACK_FAILURE; + + stream = data_s->req.protop; + if(!stream) { + failf(data_s, "Internal NULL stream! 5\n"); + return NGHTTP2_ERR_CALLBACK_FAILURE; } - if(c->bodystarted) { + if(stream->bodystarted) /* Ignore trailer or HEADERS not mapped to HTTP semantics. The consequence is handled in on_frame_recv(). */ return 0; - } - goodname = nghttp2_check_header_name(name, namelen); - goodheader = nghttp2_check_header_value(value, valuelen); + /* Store received PUSH_PROMISE headers to be used when the subsequent + PUSH_PROMISE callback comes */ + if(frame->hd.type == NGHTTP2_PUSH_PROMISE) { + char *h; - if(!goodname || !goodheader) { - - infof(conn->data, "Detected bad incoming header %s%s, reset stream!\n", - goodname?"":"name", - goodheader?"":"value"); - - rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE, - frame->hd.stream_id, - NGHTTP2_PROTOCOL_ERROR); - - if(nghttp2_is_fatal(rv)) { - return NGHTTP2_ERR_CALLBACK_FAILURE; + if(!stream->push_headers) { + stream->push_headers_alloc = 10; + stream->push_headers = malloc(stream->push_headers_alloc * + sizeof(char *)); + stream->push_headers_used = 0; } - - return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; - } - - if(namelen == sizeof(":status") - 1 && - memcmp(STATUS, name, namelen) == 0) { - - /* :status must appear exactly once. */ - if(c->status_code != -1 || - (c->status_code = decode_status_code(value, valuelen)) == -1) { - - rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE, - frame->hd.stream_id, - NGHTTP2_PROTOCOL_ERROR); - if(nghttp2_is_fatal(rv)) { - return NGHTTP2_ERR_CALLBACK_FAILURE; + else if(stream->push_headers_used == + stream->push_headers_alloc) { + char **headp; + stream->push_headers_alloc *= 2; + headp = realloc(stream->push_headers, + stream->push_headers_alloc * sizeof(char *)); + if(!headp) { + free(stream->push_headers); + stream->push_headers = NULL; + return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; } - - return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; + stream->push_headers = headp; } - - Curl_add_buffer(c->header_recvbuf, "HTTP/2.0 ", 9); - Curl_add_buffer(c->header_recvbuf, value, valuelen); - Curl_add_buffer(c->header_recvbuf, "\r\n", 2); - + h = aprintf("%s:%s", name, value); + if(h) + stream->push_headers[stream->push_headers_used++] = h; return 0; } - else { - /* Here we are sure that namelen > 0 because of - nghttp2_check_header_name(). Pseudo header other than :status - is illegal. */ - if(c->status_code == -1 || name[0] == ':') { - rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE, - frame->hd.stream_id, - NGHTTP2_PROTOCOL_ERROR); - if(nghttp2_is_fatal(rv)) { - return NGHTTP2_ERR_CALLBACK_FAILURE; - } - return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; - } + if(namelen == sizeof(":status") - 1 && + memcmp(":status", name, namelen) == 0) { + /* nghttp2 guarantees :status is received first and only once, and + value is 3 digits status code, and decode_status_code always + succeeds. */ + stream->status_code = decode_status_code(value, valuelen); + DEBUGASSERT(stream->status_code != -1); + + Curl_add_buffer(stream->header_recvbuf, "HTTP/2.0 ", 9); + Curl_add_buffer(stream->header_recvbuf, value, valuelen); + Curl_add_buffer(stream->header_recvbuf, "\r\n", 2); + data_s->state.drain++; + Curl_expire(data_s, 1); + + DEBUGF(infof(data_s, "h2 status: HTTP/2 %03d\n", + stream->status_code)); + return 0; + } - /* convert to a HTTP1-style header */ - Curl_add_buffer(c->header_recvbuf, name, namelen); - Curl_add_buffer(c->header_recvbuf, ":", 1); - Curl_add_buffer(c->header_recvbuf, value, valuelen); - Curl_add_buffer(c->header_recvbuf, "\r\n", 2); + /* nghttp2 guarantees that namelen > 0, and :status was already + received, and this is not pseudo-header field . */ + /* convert to a HTTP1-style header */ + Curl_add_buffer(stream->header_recvbuf, name, namelen); + Curl_add_buffer(stream->header_recvbuf, ":", 1); + Curl_add_buffer(stream->header_recvbuf, value, valuelen); + Curl_add_buffer(stream->header_recvbuf, "\r\n", 2); + data_s->state.drain++; + Curl_expire(data_s, 1); - infof(conn->data, "got http2 header: %.*s: %.*s\n", - namelen, name, valuelen, value); - } + DEBUGF(infof(data_s, "h2 header: %.*s: %.*s\n", namelen, name, valuelen, + value)); return 0; /* 0 is successful */ } @@ -512,26 +796,45 @@ static ssize_t data_source_read_callback(nghttp2_session *session, nghttp2_data_source *source, void *userp) { - struct connectdata *conn = (struct connectdata *)userp; - struct http_conn *c = &conn->proto.httpc; + struct SessionHandle *data_s; + struct HTTP *stream = NULL; size_t nread; - (void)session; - (void)stream_id; (void)source; + (void)userp; + + if(stream_id) { + /* get the stream from the hash based on Stream ID, stream ID zero is for + connection-oriented stuff */ + data_s = nghttp2_session_get_stream_user_data(session, stream_id); + if(!data_s) + /* Receiving a Stream ID not in the hash should not happen, this is an + internal error more than anything else! */ + return NGHTTP2_ERR_CALLBACK_FAILURE; - nread = c->upload_len < length ? c->upload_len : length; + stream = data_s->req.protop; + if(!stream) + return NGHTTP2_ERR_CALLBACK_FAILURE; + } + else + return NGHTTP2_ERR_INVALID_ARGUMENT; + + nread = MIN(stream->upload_len, length); if(nread > 0) { - memcpy(buf, c->upload_mem, nread); - c->upload_mem += nread; - c->upload_len -= nread; - c->upload_left -= nread; + memcpy(buf, stream->upload_mem, nread); + stream->upload_mem += nread; + stream->upload_len -= nread; + stream->upload_left -= nread; } - if(c->upload_left == 0) + if(stream->upload_left == 0) *data_flags = 1; else if(nread == 0) return NGHTTP2_ERR_DEFERRED; + DEBUGF(infof(data_s, "data_source_read_callback: " + "returns %zu bytes stream %u\n", + nread, stream_id)); + return nread; } @@ -543,7 +846,7 @@ static nghttp2_settings_entry settings[] = { { NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE, NGHTTP2_INITIAL_WINDOW_SIZE }, }; -#define H2_BUFSIZE 4096 +#define H2_BUFSIZE 32768 /* * Initialize nghttp2 for a Curl connection @@ -595,8 +898,7 @@ CURLcode Curl_http2_init(struct connectdata *conn) nghttp2_session_callbacks_set_on_header_callback(callbacks, on_header); /* The nghttp2 session is not yet setup, do it */ - rc = nghttp2_session_client_new(&conn->proto.httpc.h2, - callbacks, conn); + rc = nghttp2_session_client_new(&conn->proto.httpc.h2, callbacks, conn); nghttp2_session_callbacks_del(callbacks); @@ -604,6 +906,11 @@ CURLcode Curl_http2_init(struct connectdata *conn) failf(conn->data, "Couldn't initialize nghttp2!"); return CURLE_OUT_OF_MEMORY; /* most likely at least */ } + + if(rc) { + failf(conn->data, "Couldn't init stream hash!"); + return CURLE_OUT_OF_MEMORY; /* most likely at least */ + } } return CURLE_OK; } @@ -630,14 +937,6 @@ CURLcode Curl_http2_request_upgrade(Curl_send_buffer *req, struct SingleRequest *k = &conn->data->req; uint8_t *binsettings = conn->proto.httpc.binsettings; - result = Curl_http2_init(conn); - if(result) - return result; - - result = Curl_http2_setup(conn); - if(result) - return result; - /* As long as we have a fixed set of settings, we don't have to dynamically * figure out the base64 strings since it'll always be the same. However, * the settings will likely not be fixed every time in the future. @@ -663,13 +962,32 @@ CURLcode Curl_http2_request_upgrade(Curl_send_buffer *req, "Upgrade: %s\r\n" "HTTP2-Settings: %s\r\n", NGHTTP2_CLEARTEXT_PROTO_VERSION_ID, base64); - Curl_safefree(base64); + free(base64); k->upgr101 = UPGR101_REQUESTED; return result; } +static ssize_t http2_handle_stream_close(struct http_conn *httpc, + struct SessionHandle *data, + struct HTTP *stream, CURLcode *err) { + if(httpc->pause_stream_id == stream->stream_id) { + httpc->pause_stream_id = 0; + } + /* Reset to FALSE to prevent infinite loop in readwrite_data + function. */ + stream->closed = FALSE; + if(stream->error_code != NGHTTP2_NO_ERROR) { + failf(data, "HTTP/2 stream %u was not closed cleanly: error_code = %d", + stream->stream_id, stream->error_code); + *err = CURLE_HTTP2; + return -1; + } + DEBUGF(infof(data, "http2_recv returns 0, http2_handle_stream_close\n")); + return 0; +} + /* * If the read would block (EWOULDBLOCK) we return -1. Otherwise we return * a regular CURLcode value. @@ -677,102 +995,188 @@ CURLcode Curl_http2_request_upgrade(Curl_send_buffer *req, static ssize_t http2_recv(struct connectdata *conn, int sockindex, char *mem, size_t len, CURLcode *err) { - CURLcode rc; + CURLcode result = CURLE_OK; ssize_t rv; ssize_t nread; struct http_conn *httpc = &conn->proto.httpc; + struct SessionHandle *data = conn->data; + struct HTTP *stream = data->req.protop; (void)sockindex; /* we always do HTTP2 on sockindex 0 */ - if(httpc->closed) { - /* Reset to FALSE to prevent infinite loop in readwrite_data - function. */ - httpc->closed = FALSE; - return 0; + /* If stream is closed, return 0 to signal the http routine to close + the connection. We need to handle stream closure here, + otherwise, we may be going to read from underlying connection, + and gets EAGAIN, and we will get stuck there. */ + if(stream->memlen == 0 && stream->closed) { + return http2_handle_stream_close(httpc, data, stream, err); } /* Nullify here because we call nghttp2_session_send() and they might refer to the old buffer. */ - httpc->upload_mem = NULL; - httpc->upload_len = 0; + stream->upload_mem = NULL; + stream->upload_len = 0; - if(httpc->bodystarted && - httpc->nread_header_recvbuf < httpc->header_recvbuf->size_used) { + /* + * At this point 'stream' is just in the SessionHandle the connection + * identifies as its owner at this time. + */ + + if(stream->bodystarted && + stream->nread_header_recvbuf < stream->header_recvbuf->size_used) { + /* If there is body data pending for this stream to return, do that */ size_t left = - httpc->header_recvbuf->size_used - httpc->nread_header_recvbuf; - size_t ncopy = len < left ? len : left; - memcpy(mem, httpc->header_recvbuf->buffer + httpc->nread_header_recvbuf, + stream->header_recvbuf->size_used - stream->nread_header_recvbuf; + size_t ncopy = MIN(len, left); + memcpy(mem, stream->header_recvbuf->buffer + stream->nread_header_recvbuf, ncopy); - httpc->nread_header_recvbuf += ncopy; + stream->nread_header_recvbuf += ncopy; + + infof(data, "http2_recv: Got %d bytes from header_recvbuf\n", + (int)ncopy); return ncopy; } - if(httpc->data) { - nread = len < httpc->datalen ? len : httpc->datalen; - memcpy(mem, httpc->data, nread); + infof(data, "http2_recv: %d bytes buffer at %p (stream %u)\n", + len, mem, stream->stream_id); + + if((data->state.drain) && stream->memlen) { + DEBUGF(infof(data, "http2_recv: DRAIN %zu bytes stream %u!! (%p => %p)\n", + stream->memlen, stream->stream_id, + stream->mem, mem)); + if(mem != stream->mem) { + /* if we didn't get the same buffer this time, we must move the data to + the beginning */ + memmove(mem, stream->mem, stream->memlen); + stream->len = len - stream->memlen; + stream->mem = mem; + } + } + else if(stream->pausedata) { + nread = MIN(len, stream->pauselen); + memcpy(mem, stream->pausedata, nread); + + stream->pausedata += nread; + stream->pauselen -= nread; - httpc->data += nread; - httpc->datalen -= nread; + infof(data, "%zu data bytes written\n", nread); + if(stream->pauselen == 0) { + DEBUGF(infof(data, "Unpaused by stream %u\n", stream->stream_id)); + assert(httpc->pause_stream_id == stream->stream_id); + httpc->pause_stream_id = 0; - infof(conn->data, "%zu data written\n", nread); - if(httpc->datalen == 0) { - httpc->data = NULL; - httpc->datalen = 0; + stream->pausedata = NULL; + stream->pauselen = 0; } + infof(data, "http2_recv: returns unpaused %zd bytes on stream %u\n", + nread, stream->stream_id); return nread; } + else if(httpc->pause_stream_id) { + /* If a stream paused nghttp2_session_mem_recv previously, and has + not processed all data, it still refers to the buffer in + nghttp2_session. If we call nghttp2_session_mem_recv(), we may + overwrite that buffer. To avoid that situation, just return + here with CURLE_AGAIN. This could be busy loop since data in + socket is not read. But it seems that usually streams are + notified with its drain property, and socket is read again + quickly. */ + *err = CURLE_AGAIN; + return -1; + } + else { + char *inbuf; + /* remember where to store incoming data for this stream and how big the + buffer is */ + stream->mem = mem; + stream->len = len; + stream->memlen = 0; + + if(httpc->inbuflen == 0) { + nread = ((Curl_recv *)httpc->recv_underlying)( + conn, FIRSTSOCKET, httpc->inbuf, H2_BUFSIZE, &result); + + if(result == CURLE_AGAIN) { + *err = result; + return -1; + } - conn->proto.httpc.mem = mem; - conn->proto.httpc.len = len; - - infof(conn->data, "http2_recv: %d bytes buffer\n", - conn->proto.httpc.len); + if(nread == -1) { + failf(data, "Failed receiving HTTP2 data"); + *err = result; + return 0; + } - rc = 0; - nread = ((Curl_recv*)httpc->recv_underlying)(conn, FIRSTSOCKET, - httpc->inbuf, H2_BUFSIZE, &rc); + if(nread == 0) { + failf(data, "Unexpected EOF"); + *err = CURLE_RECV_ERROR; + return -1; + } - if(rc == CURLE_AGAIN) { - *err = rc; - return -1; - } + DEBUGF(infof(data, "nread=%zd\n", nread)); - if(nread == -1) { - failf(conn->data, "Failed receiving HTTP2 data"); - *err = rc; - return 0; - } + httpc->inbuflen = nread; + inbuf = httpc->inbuf; + } + else { + nread = httpc->inbuflen - httpc->nread_inbuf; + inbuf = httpc->inbuf + httpc->nread_inbuf; - infof(conn->data, "nread=%zd\n", nread); - rv = nghttp2_session_mem_recv(httpc->h2, - (const uint8_t *)httpc->inbuf, nread); + DEBUGF(infof(data, "Use data left in connection buffer, nread=%zd\n", + nread)); + } + rv = nghttp2_session_mem_recv(httpc->h2, (const uint8_t *)inbuf, nread); - if(nghttp2_is_fatal((int)rv)) { - failf(conn->data, "nghttp2_session_mem_recv() returned %d:%s\n", - rv, nghttp2_strerror((int)rv)); - *err = CURLE_RECV_ERROR; - return 0; - } - infof(conn->data, "nghttp2_session_mem_recv() returns %zd\n", rv); - /* Always send pending frames in nghttp2 session, because - nghttp2_session_mem_recv() may queue new frame */ - rv = nghttp2_session_send(httpc->h2); - if(rv != 0) { - *err = CURLE_SEND_ERROR; - return 0; + if(nghttp2_is_fatal((int)rv)) { + failf(data, "nghttp2_session_mem_recv() returned %d:%s\n", + rv, nghttp2_strerror((int)rv)); + *err = CURLE_RECV_ERROR; + return 0; + } + DEBUGF(infof(data, "nghttp2_session_mem_recv() returns %zd\n", rv)); + if(nread == rv) { + DEBUGF(infof(data, "All data in connection buffer processed\n")); + httpc->inbuflen = 0; + httpc->nread_inbuf = 0; + } + else { + httpc->nread_inbuf += rv; + DEBUGF(infof(data, "%zu bytes left in connection buffer\n", + httpc->inbuflen - httpc->nread_inbuf)); + } + /* Always send pending frames in nghttp2 session, because + nghttp2_session_mem_recv() may queue new frame */ + rv = nghttp2_session_send(httpc->h2); + if(rv != 0) { + *err = CURLE_SEND_ERROR; + return 0; + } } - if(len != httpc->len) { - return len - conn->proto.httpc.len; + if(stream->memlen) { + ssize_t retlen = stream->memlen; + infof(data, "http2_recv: returns %zd for stream %u\n", + retlen, stream->stream_id); + stream->memlen = 0; + + if(httpc->pause_stream_id == stream->stream_id) { + /* data for this stream is returned now, but this stream caused a pause + already so we need it called again asap */ + DEBUGF(infof(data, "Data returned for PAUSED stream %u\n", + stream->stream_id)); + } + else + data->state.drain = 0; /* this stream is hereby drained */ + + return retlen; } /* If stream is closed, return 0 to signal the http routine to close the connection */ - if(httpc->closed) { - /* Reset to FALSE to prevent infinite loop in readwrite_data - function. */ - httpc->closed = FALSE; - return 0; + if(stream->closed) { + return http2_handle_stream_close(httpc, data, stream, err); } *err = CURLE_AGAIN; + DEBUGF(infof(data, "http2_recv returns AGAIN for stream %u\n", + stream->stream_id)); return -1; } @@ -791,6 +1195,7 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex, */ int rv; struct http_conn *httpc = &conn->proto.httpc; + struct HTTP *stream = conn->data->req.protop; nghttp2_nv *nva; size_t nheader; size_t i; @@ -799,23 +1204,41 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex, char *end; nghttp2_data_provider data_prd; int32_t stream_id; + nghttp2_session *h2 = httpc->h2; (void)sockindex; - infof(conn->data, "http2_send len=%zu\n", len); + DEBUGF(infof(conn->data, "http2_send len=%zu\n", len)); - if(httpc->stream_id != -1) { + if(stream->stream_id != -1) { /* If stream_id != -1, we have dispatched request HEADERS, and now are going to send or sending request body in DATA frame */ - httpc->upload_mem = mem; - httpc->upload_len = len; - nghttp2_session_resume_data(httpc->h2, httpc->stream_id); - rv = nghttp2_session_send(httpc->h2); + stream->upload_mem = mem; + stream->upload_len = len; + nghttp2_session_resume_data(h2, stream->stream_id); + rv = nghttp2_session_send(h2); if(nghttp2_is_fatal(rv)) { *err = CURLE_SEND_ERROR; return -1; } - return len - httpc->upload_len; + len -= stream->upload_len; + + /* Nullify here because we call nghttp2_session_send() and they + might refer to the old buffer. */ + stream->upload_mem = NULL; + stream->upload_len = 0; + + if(stream->upload_left) { + /* we are sure that we have more data to send here. Calling the + following API will make nghttp2_session_want_write() return + nonzero if remote window allows it, which then libcurl checks + socket is writable or not. See http2_perform_getsock(). */ + nghttp2_session_resume_data(h2, stream->stream_id); + } + + DEBUGF(infof(conn->data, "http2_send returns %zu for stream %u\n", len, + stream->stream_id)); + return len; } /* Calculate number of headers contained in [mem, mem + len) */ @@ -838,6 +1261,8 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex, } /* Extract :method, :path from request line */ end = strchr(hdbuf, ' '); + if(!end) + goto fail; nva[0].name = (unsigned char *)":method"; nva[0].namelen = (uint16_t)strlen((char *)nva[0].name); nva[0].value = (unsigned char *)hdbuf; @@ -847,6 +1272,8 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex, hdbuf = end + 1; end = strchr(hdbuf, ' '); + if(!end) + goto fail; nva[1].name = (unsigned char *)":path"; nva[1].namelen = (uint16_t)strlen((char *)nva[1].name); nva[1].value = (unsigned char *)hdbuf; @@ -863,13 +1290,16 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex, nva[2].flags = NGHTTP2_NV_FLAG_NONE; hdbuf = strchr(hdbuf, 0x0a); + if(!hdbuf) + goto fail; ++hdbuf; authority_idx = 0; for(i = 3; i < nheader; ++i) { end = strchr(hdbuf, ':'); - assert(end); + if(!end) + goto fail; if(end - hdbuf == 4 && Curl_raw_nequal("host", hdbuf, 4)) { authority_idx = i; nva[i].name = (unsigned char *)":authority"; @@ -882,7 +1312,8 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex, hdbuf = end + 1; for(; *hdbuf == ' '; ++hdbuf); end = strchr(hdbuf, 0x0d); - assert(end); + if(!end) + goto fail; nva[i].value = (unsigned char *)hdbuf; nva[i].valuelen = (uint16_t)(end - hdbuf); nva[i].flags = NGHTTP2_NV_FLAG_NONE; @@ -894,11 +1325,15 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex, if(nva[i].namelen == 14 && Curl_raw_nequal("content-length", (char*)nva[i].name, 14)) { size_t j; + stream->upload_left = 0; for(j = 0; j < nva[i].valuelen; ++j) { - httpc->upload_left *= 10; - httpc->upload_left += nva[i].value[j] - '0'; + stream->upload_left *= 10; + stream->upload_left += nva[i].value[j] - '0'; } - infof(conn->data, "request content-length=%zu\n", httpc->upload_left); + DEBUGF(infof(conn->data, + "request content-length=%" + CURL_FORMAT_CURL_OFF_T + "\n", stream->upload_left)); } } @@ -917,31 +1352,34 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex, case HTTPREQ_PUT: data_prd.read_callback = data_source_read_callback; data_prd.source.ptr = NULL; - stream_id = nghttp2_submit_request(httpc->h2, NULL, nva, nheader, - &data_prd, NULL); + stream_id = nghttp2_submit_request(h2, NULL, nva, nheader, + &data_prd, conn->data); break; default: - stream_id = nghttp2_submit_request(httpc->h2, NULL, nva, nheader, - NULL, NULL); + stream_id = nghttp2_submit_request(h2, NULL, nva, nheader, + NULL, conn->data); } Curl_safefree(nva); if(stream_id < 0) { + DEBUGF(infof(conn->data, "http2_send() send error\n")); *err = CURLE_SEND_ERROR; return -1; } - httpc->stream_id = stream_id; + infof(conn->data, "Using Stream ID: %x (easy handle %p)\n", + stream_id, conn->data); + stream->stream_id = stream_id; - rv = nghttp2_session_send(httpc->h2); + rv = nghttp2_session_send(h2); if(rv != 0) { *err = CURLE_SEND_ERROR; return -1; } - if(httpc->stream_id != -1) { + if(stream->stream_id != -1) { /* If whole HEADERS frame was sent off to the underlying socket, the nghttp2 library calls data_source_read_callback. But only it found that no data available, so it deferred the DATA @@ -950,67 +1388,83 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex, writable socket check is performed. To workaround this, we issue nghttp2_session_resume_data() here to bring back DATA transmission from deferred state. */ - nghttp2_session_resume_data(httpc->h2, httpc->stream_id); + nghttp2_session_resume_data(h2, stream->stream_id); } return len; + + fail: + free(nva); + *err = CURLE_SEND_ERROR; + return -1; } CURLcode Curl_http2_setup(struct connectdata *conn) { + CURLcode result; struct http_conn *httpc = &conn->proto.httpc; + struct HTTP *stream = conn->data->req.protop; + + stream->stream_id = -1; + + if(!stream->header_recvbuf) + stream->header_recvbuf = Curl_add_buffer_init(); + + if((conn->handler == &Curl_handler_http2_ssl) || + (conn->handler == &Curl_handler_http2)) + return CURLE_OK; /* already done */ + if(conn->handler->flags & PROTOPT_SSL) conn->handler = &Curl_handler_http2_ssl; else conn->handler = &Curl_handler_http2; - infof(conn->data, "Using HTTP2\n"); - httpc->bodystarted = FALSE; - httpc->closed = FALSE; - httpc->header_recvbuf = Curl_add_buffer_init(); - httpc->nread_header_recvbuf = 0; - httpc->data = NULL; - httpc->datalen = 0; - httpc->upload_left = 0; - httpc->upload_mem = NULL; - httpc->upload_len = 0; - httpc->stream_id = -1; - httpc->status_code = -1; + result = Curl_http2_init(conn); + if(result) + return result; + + infof(conn->data, "Using HTTP2, server supports multi-use\n"); + stream->upload_left = 0; + stream->upload_mem = NULL; + stream->upload_len = 0; + httpc->inbuflen = 0; + httpc->nread_inbuf = 0; + + httpc->pause_stream_id = 0; + + conn->bits.multiplex = TRUE; /* at least potentially multiplexed */ conn->httpversion = 20; + conn->bundle->multiuse = BUNDLE_MULTIPLEX; - return 0; + infof(conn->data, "Connection state changed (HTTP/2 confirmed)\n"); + Curl_multi_connchanged(conn->data->multi); + + return CURLE_OK; } -CURLcode Curl_http2_switched(struct connectdata *conn) +CURLcode Curl_http2_switched(struct connectdata *conn, + const char *mem, size_t nread) { - CURLcode rc; + CURLcode result; struct http_conn *httpc = &conn->proto.httpc; int rv; + ssize_t nproc; struct SessionHandle *data = conn->data; + struct HTTP *stream = conn->data->req.protop; + + result = Curl_http2_setup(conn); + if(result) + return result; httpc->recv_underlying = (recving)conn->recv[FIRSTSOCKET]; httpc->send_underlying = (sending)conn->send[FIRSTSOCKET]; conn->recv[FIRSTSOCKET] = http2_recv; conn->send[FIRSTSOCKET] = http2_send; - rv = (int) ((Curl_send*)httpc->send_underlying) - (conn, FIRSTSOCKET, - NGHTTP2_CLIENT_CONNECTION_PREFACE, - NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN, - &rc); - if(rc) - /* TODO: This may get CURLE_AGAIN */ - return rc; - - if(rv != 24) { - failf(data, "Only sent partial HTTP2 packet"); - return CURLE_SEND_ERROR; - } - if(conn->data->req.upgr101 == UPGR101_RECEIVED) { /* stream 1 is opened implicitly on upgrade */ - httpc->stream_id = 1; + stream->stream_id = 1; /* queue SETTINGS frame (again) */ rv = nghttp2_session_upgrade(httpc->h2, httpc->binsettings, httpc->binlen, NULL); @@ -1019,10 +1473,14 @@ CURLcode Curl_http2_switched(struct connectdata *conn) nghttp2_strerror(rv), rv); return CURLE_HTTP2; } + + nghttp2_session_set_stream_user_data(httpc->h2, + stream->stream_id, + conn->data); } else { /* stream ID is unknown at this point */ - httpc->stream_id = -1; + stream->stream_id = -1; rv = nghttp2_submit_settings(httpc->h2, NGHTTP2_FLAG_NONE, NULL, 0); if(rv != 0) { failf(data, "nghttp2_submit_settings() failed: %s(%d)", @@ -1030,7 +1488,75 @@ CURLcode Curl_http2_switched(struct connectdata *conn) return CURLE_HTTP2; } } + + /* we are going to copy mem to httpc->inbuf. This is required since + mem is part of buffer pointed by stream->mem, and callbacks + called by nghttp2_session_mem_recv() will write stream specific + data into stream->mem, overwriting data already there. */ + if(H2_BUFSIZE < nread) { + failf(data, "connection buffer size is too small to store data following " + "HTTP Upgrade response header: buflen=%zu, datalen=%zu", + H2_BUFSIZE, nread); + return CURLE_HTTP2; + } + + infof(conn->data, "Copying HTTP/2 data in stream buffer to connection buffer" + " after upgrade: len=%zu\n", + nread); + + memcpy(httpc->inbuf, mem, nread); + httpc->inbuflen = nread; + + nproc = nghttp2_session_mem_recv(httpc->h2, (const uint8_t *)httpc->inbuf, + httpc->inbuflen); + + if(nghttp2_is_fatal((int)nproc)) { + failf(data, "nghttp2_session_mem_recv() failed: %s(%d)", + nghttp2_strerror((int)nproc), (int)nproc); + return CURLE_HTTP2; + } + + DEBUGF(infof(data, "nghttp2_session_mem_recv() returns %zd\n", nproc)); + + if((ssize_t)nread == nproc) { + httpc->inbuflen = 0; + httpc->nread_inbuf = 0; + } + else { + httpc->nread_inbuf += nproc; + } + + /* Try to send some frames since we may read SETTINGS already. */ + rv = nghttp2_session_send(httpc->h2); + + if(rv != 0) { + failf(data, "nghttp2_session_send() failed: %s(%d)", + nghttp2_strerror(rv), rv); + return CURLE_HTTP2; + } + return CURLE_OK; } -#endif +#else /* !USE_NGHTTP2 */ + +/* Satisfy external references even if http2 is not compiled in. */ + +#define CURL_DISABLE_TYPECHECK +#include <curl/curl.h> + +char *curl_pushheader_bynum(struct curl_pushheaders *h, size_t num) +{ + (void) h; + (void) num; + return NULL; +} + +char *curl_pushheader_byname(struct curl_pushheaders *h, const char *header) +{ + (void) h; + (void) header; + return NULL; +} + +#endif /* USE_NGHTTP2 */ diff --git a/Utilities/cmcurl/lib/http2.h b/Utilities/cmcurl/lib/http2.h index 66aa6fd..bb7ad9c 100644 --- a/Utilities/cmcurl/lib/http2.h +++ b/Utilities/cmcurl/lib/http2.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -26,6 +26,11 @@ #ifdef USE_NGHTTP2 #include "http.h" + +/* value for MAX_CONCURRENT_STREAMS we use until we get an updated setting + from the peer */ +#define DEFAULT_MAX_CONCURRENT_STREAMS 13 + /* * Store nghttp2 version info in this buffer, Prefix with a space. Return * total length written. @@ -37,13 +42,19 @@ CURLcode Curl_http2_send_request(struct connectdata *conn); CURLcode Curl_http2_request_upgrade(Curl_send_buffer *req, struct connectdata *conn); CURLcode Curl_http2_setup(struct connectdata *conn); -CURLcode Curl_http2_switched(struct connectdata *conn); +CURLcode Curl_http2_switched(struct connectdata *conn, + const char *data, size_t nread); +/* called from Curl_http_setup_conn */ +void Curl_http2_setup_conn(struct connectdata *conn); +void Curl_http2_setup_req(struct SessionHandle *data); #else /* USE_NGHTTP2 */ #define Curl_http2_init(x) CURLE_UNSUPPORTED_PROTOCOL #define Curl_http2_send_request(x) CURLE_UNSUPPORTED_PROTOCOL #define Curl_http2_request_upgrade(x,y) CURLE_UNSUPPORTED_PROTOCOL #define Curl_http2_setup(x) CURLE_UNSUPPORTED_PROTOCOL -#define Curl_http2_switched(x) CURLE_UNSUPPORTED_PROTOCOL +#define Curl_http2_switched(x,y,z) CURLE_UNSUPPORTED_PROTOCOL +#define Curl_http2_setup_conn(x) +#define Curl_http2_setup_req(x) #endif #endif /* HEADER_CURL_HTTP2_H */ diff --git a/Utilities/cmcurl/lib/http_chunks.c b/Utilities/cmcurl/lib/http_chunks.c index 61a6098..7e91b37 100644 --- a/Utilities/cmcurl/lib/http_chunks.c +++ b/Utilities/cmcurl/lib/http_chunks.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -29,15 +29,12 @@ #include "content_encoding.h" #include "http.h" -#include "curl_memory.h" #include "non-ascii.h" /* for Curl_convert_to_network prototype */ #include "strtoofft.h" #include "warnless.h" -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - -/* The last #include file should be: */ +/* The last #include files should be: */ +#include "curl_memory.h" #include "memdebug.h" /* @@ -158,7 +155,7 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn, if(result) { /* Curl_convert_from_network calls failf if unsuccessful */ /* Treat it as a bad hex character */ - return CHUNKE_ILLEGAL_HEX ; + return CHUNKE_ILLEGAL_HEX; } ch->datasize=curlx_strtoofft(ch->hexbuffer, &endptr, 16); @@ -221,7 +218,6 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn, (ssize_t)piece); break; - case COMPRESS: default: failf (conn->data, "Unrecognized content encoding type. " diff --git a/Utilities/cmcurl/lib/http_digest.c b/Utilities/cmcurl/lib/http_digest.c index 55f5108..929e2c6 100644 --- a/Utilities/cmcurl/lib/http_digest.c +++ b/Utilities/cmcurl/lib/http_digest.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -26,94 +26,14 @@ #include "urldata.h" #include "rawstr.h" -#include "curl_base64.h" -#include "curl_md5.h" +#include "curl_sasl.h" #include "http_digest.h" -#include "strtok.h" -#include "curl_memory.h" -#include "vtls/vtls.h" /* for Curl_rand() */ -#include "non-ascii.h" /* included for Curl_convert_... prototypes */ -#include "warnless.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> +#include "curl_printf.h" -/* The last #include file should be: */ +/* The last #include files should be: */ +#include "curl_memory.h" #include "memdebug.h" -#define MAX_VALUE_LENGTH 256 -#define MAX_CONTENT_LENGTH 1024 - -static void digest_cleanup_one(struct digestdata *dig); - -/* - * Return 0 on success and then the buffers are filled in fine. - * - * Non-zero means failure to parse. - */ -static int get_pair(const char *str, char *value, char *content, - const char **endptr) -{ - int c; - bool starts_with_quote = FALSE; - bool escape = FALSE; - - for(c=MAX_VALUE_LENGTH-1; (*str && (*str != '=') && c--); ) - *value++ = *str++; - *value=0; - - if('=' != *str++) - /* eek, no match */ - return 1; - - if('\"' == *str) { - /* this starts with a quote so it must end with one as well! */ - str++; - starts_with_quote = TRUE; - } - - for(c=MAX_CONTENT_LENGTH-1; *str && c--; str++) { - switch(*str) { - case '\\': - if(!escape) { - /* possibly the start of an escaped quote */ - escape = TRUE; - *content++ = '\\'; /* even though this is an escape character, we still - store it as-is in the target buffer */ - continue; - } - break; - case ',': - if(!starts_with_quote) { - /* this signals the end of the content if we didn't get a starting - quote and then we do "sloppy" parsing */ - c=0; /* the end */ - continue; - } - break; - case '\r': - case '\n': - /* end of string */ - c=0; - continue; - case '\"': - if(!escape && starts_with_quote) { - /* end of string */ - c=0; - continue; - } - break; - } - escape = FALSE; - *content++ = *str; - } - *content=0; - - *endptr = str; - - return 0; /* all is fine! */ -} - /* Test example headers: WWW-Authenticate: Digest realm="testrealm", nonce="1053604598" @@ -121,177 +41,31 @@ Proxy-Authenticate: Digest realm="testrealm", nonce="1053604598" */ -CURLdigest Curl_input_digest(struct connectdata *conn, - bool proxy, - const char *header) /* rest of the *-authenticate: - header */ +CURLcode Curl_input_digest(struct connectdata *conn, + bool proxy, + const char *header) /* rest of the *-authenticate: + header */ { - char *token = NULL; - char *tmp = NULL; - bool foundAuth = FALSE; - bool foundAuthInt = FALSE; - struct SessionHandle *data=conn->data; - bool before = FALSE; /* got a nonce before */ - struct digestdata *d; + struct SessionHandle *data = conn->data; + + /* Point to the correct struct with this */ + struct digestdata *digest; if(proxy) { - d = &data->state.proxydigest; + digest = &data->state.proxydigest; } else { - d = &data->state.digest; - } - - if(checkprefix("Digest", header)) { - header += strlen("Digest"); - - /* If we already have received a nonce, keep that in mind */ - if(d->nonce) - before = TRUE; - - /* clear off any former leftovers and init to defaults */ - digest_cleanup_one(d); - - for(;;) { - char value[MAX_VALUE_LENGTH]; - char content[MAX_CONTENT_LENGTH]; - - while(*header && ISSPACE(*header)) - header++; - - /* extract a value=content pair */ - if(!get_pair(header, value, content, &header)) { - if(Curl_raw_equal(value, "nonce")) { - d->nonce = strdup(content); - if(!d->nonce) - return CURLDIGEST_NOMEM; - } - else if(Curl_raw_equal(value, "stale")) { - if(Curl_raw_equal(content, "true")) { - d->stale = TRUE; - d->nc = 1; /* we make a new nonce now */ - } - } - else if(Curl_raw_equal(value, "realm")) { - d->realm = strdup(content); - if(!d->realm) - return CURLDIGEST_NOMEM; - } - else if(Curl_raw_equal(value, "opaque")) { - d->opaque = strdup(content); - if(!d->opaque) - return CURLDIGEST_NOMEM; - } - else if(Curl_raw_equal(value, "qop")) { - char *tok_buf; - /* tokenize the list and choose auth if possible, use a temporary - clone of the buffer since strtok_r() ruins it */ - tmp = strdup(content); - if(!tmp) - return CURLDIGEST_NOMEM; - token = strtok_r(tmp, ",", &tok_buf); - while(token != NULL) { - if(Curl_raw_equal(token, "auth")) { - foundAuth = TRUE; - } - else if(Curl_raw_equal(token, "auth-int")) { - foundAuthInt = TRUE; - } - token = strtok_r(NULL, ",", &tok_buf); - } - free(tmp); - /*select only auth o auth-int. Otherwise, ignore*/ - if(foundAuth) { - d->qop = strdup("auth"); - if(!d->qop) - return CURLDIGEST_NOMEM; - } - else if(foundAuthInt) { - d->qop = strdup("auth-int"); - if(!d->qop) - return CURLDIGEST_NOMEM; - } - } - else if(Curl_raw_equal(value, "algorithm")) { - d->algorithm = strdup(content); - if(!d->algorithm) - return CURLDIGEST_NOMEM; - if(Curl_raw_equal(content, "MD5-sess")) - d->algo = CURLDIGESTALGO_MD5SESS; - else if(Curl_raw_equal(content, "MD5")) - d->algo = CURLDIGESTALGO_MD5; - else - return CURLDIGEST_BADALGO; - } - else { - /* unknown specifier, ignore it! */ - } - } - else - break; /* we're done here */ - - /* pass all additional spaces here */ - while(*header && ISSPACE(*header)) - header++; - if(',' == *header) - /* allow the list to be comma-separated */ - header++; - } - /* We had a nonce since before, and we got another one now without - 'stale=true'. This means we provided bad credentials in the previous - request */ - if(before && !d->stale) - return CURLDIGEST_BAD; - - /* We got this header without a nonce, that's a bad Digest line! */ - if(!d->nonce) - return CURLDIGEST_BAD; + digest = &data->state.digest; } - else - /* else not a digest, get out */ - return CURLDIGEST_NONE; - - return CURLDIGEST_FINE; -} -/* convert md5 chunk to RFC2617 (section 3.1.3) -suitable ascii string*/ -static void md5_to_ascii(unsigned char *source, /* 16 bytes */ - unsigned char *dest) /* 33 bytes */ -{ - int i; - for(i=0; i<16; i++) - snprintf((char *)&dest[i*2], 3, "%02x", source[i]); -} - -/* Perform quoted-string escaping as described in RFC2616 and its errata */ -static char *string_quoted(const char *source) -{ - char *dest, *d; - const char *s = source; - size_t n = 1; /* null terminator */ - - /* Calculate size needed */ - while(*s) { - ++n; - if(*s == '"' || *s == '\\') { - ++n; - } - ++s; - } + if(!checkprefix("Digest", header)) + return CURLE_BAD_CONTENT_ENCODING; - dest = malloc(n); - if(dest) { - s = source; - d = dest; - while(*s) { - if(*s == '"' || *s == '\\') { - *d++ = '\\'; - } - *d++ = *s++; - } - *d = 0; - } + header += strlen("Digest"); + while(*header && ISSPACE(*header)) + header++; - return dest; + return Curl_sasl_decode_digest_http_message(header, digest); } CURLcode Curl_output_digest(struct connectdata *conn, @@ -299,49 +73,35 @@ CURLcode Curl_output_digest(struct connectdata *conn, const unsigned char *request, const unsigned char *uripath) { - /* We have a Digest setup for this, use it! Now, to get all the details for - this sorted out, I must urge you dear friend to read up on the RFC2617 - section 3.2.2, */ - size_t urilen; - unsigned char md5buf[16]; /* 16 bytes/128 bits */ - unsigned char request_digest[33]; - unsigned char *md5this; - unsigned char ha1[33];/* 32 digits and 1 zero byte */ - unsigned char ha2[33];/* 32 digits and 1 zero byte */ - char cnoncebuf[33]; - char *cnonce = NULL; - size_t cnonce_sz = 0; - char *tmp = NULL; + CURLcode result; + struct SessionHandle *data = conn->data; + unsigned char *path; + char *tmp; + char *response; + size_t len; + bool have_chlg; + + /* Point to the address of the pointer that holds the string to send to the + server, which is for a plain host or for a HTTP proxy */ char **allocuserpwd; - size_t userlen; + + /* Point to the name and password for this */ const char *userp; - char *userp_quoted; const char *passwdp; - struct auth *authp; - struct SessionHandle *data = conn->data; - struct digestdata *d; - CURLcode rc; -/* The CURL_OUTPUT_DIGEST_CONV macro below is for non-ASCII machines. - It converts digest text to ASCII so the MD5 will be correct for - what ultimately goes over the network. -*/ -#define CURL_OUTPUT_DIGEST_CONV(a, b) \ - rc = Curl_convert_to_network(a, (char *)b, strlen((const char*)b)); \ - if(rc != CURLE_OK) { \ - free(b); \ - return rc; \ - } + /* Point to the correct struct with this */ + struct digestdata *digest; + struct auth *authp; if(proxy) { - d = &data->state.proxydigest; + digest = &data->state.proxydigest; allocuserpwd = &conn->allocptr.proxyuserpwd; userp = conn->proxyuser; passwdp = conn->proxypasswd; authp = &data->state.authproxy; } else { - d = &data->state.digest; + digest = &data->state.digest; allocuserpwd = &conn->allocptr.userpwd; userp = conn->user; passwdp = conn->passwd; @@ -352,75 +112,21 @@ CURLcode Curl_output_digest(struct connectdata *conn, /* not set means empty */ if(!userp) - userp=""; + userp = ""; if(!passwdp) - passwdp=""; + passwdp = ""; + +#if defined(USE_WINDOWS_SSPI) + have_chlg = digest->input_token ? TRUE : FALSE; +#else + have_chlg = digest->nonce ? TRUE : FALSE; +#endif - if(!d->nonce) { + if(!have_chlg) { authp->done = FALSE; return CURLE_OK; } - authp->done = TRUE; - - if(!d->nc) - d->nc = 1; - - if(!d->cnonce) { - snprintf(cnoncebuf, sizeof(cnoncebuf), "%08x%08x%08x%08x", - Curl_rand(data), Curl_rand(data), - Curl_rand(data), Curl_rand(data)); - rc = Curl_base64_encode(data, cnoncebuf, strlen(cnoncebuf), - &cnonce, &cnonce_sz); - if(rc) - return rc; - d->cnonce = cnonce; - } - - /* - if the algorithm is "MD5" or unspecified (which then defaults to MD5): - - A1 = unq(username-value) ":" unq(realm-value) ":" passwd - - if the algorithm is "MD5-sess" then: - - A1 = H( unq(username-value) ":" unq(realm-value) ":" passwd ) - ":" unq(nonce-value) ":" unq(cnonce-value) - */ - - md5this = (unsigned char *) - aprintf("%s:%s:%s", userp, d->realm, passwdp); - if(!md5this) - return CURLE_OUT_OF_MEMORY; - - CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */ - Curl_md5it(md5buf, md5this); - Curl_safefree(md5this); - md5_to_ascii(md5buf, ha1); - - if(d->algo == CURLDIGESTALGO_MD5SESS) { - /* nonce and cnonce are OUTSIDE the hash */ - tmp = aprintf("%s:%s:%s", ha1, d->nonce, d->cnonce); - if(!tmp) - return CURLE_OUT_OF_MEMORY; - CURL_OUTPUT_DIGEST_CONV(data, tmp); /* convert on non-ASCII machines */ - Curl_md5it(md5buf, (unsigned char *)tmp); - Curl_safefree(tmp); - md5_to_ascii(md5buf, ha1); - } - - /* - If the "qop" directive's value is "auth" or is unspecified, then A2 is: - - A2 = Method ":" digest-uri-value - - If the "qop" value is "auth-int", then A2 is: - - A2 = Method ":" digest-uri-value ":" H(entity-body) - - (The "Method" value is the HTTP request method as specified in section - 5.1.1 of RFC 2616) - */ /* So IE browsers < v7 cut off the URI part at the query part when they evaluate the MD5 and some (IIS?) servers work with them so we may need to @@ -435,164 +141,39 @@ CURLcode Curl_output_digest(struct connectdata *conn, http://www.fngtps.com/2006/09/http-authentication */ - if(authp->iestyle && ((tmp = strchr((char *)uripath, '?')) != NULL)) - urilen = tmp - (char *)uripath; - else - urilen = strlen((char *)uripath); - - md5this = (unsigned char *)aprintf("%s:%.*s", request, urilen, uripath); + if(authp->iestyle && ((tmp = strchr((char *)uripath, '?')) != NULL)) { + size_t urilen = tmp - (char *)uripath; - if(d->qop && Curl_raw_equal(d->qop, "auth-int")) { - /* We don't support auth-int for PUT or POST at the moment. - TODO: replace md5 of empty string with entity-body for PUT/POST */ - unsigned char *md5this2 = (unsigned char *) - aprintf("%s:%s", md5this, "d41d8cd98f00b204e9800998ecf8427e"); - Curl_safefree(md5this); - md5this = md5this2; + path = (unsigned char *) aprintf("%.*s", urilen, uripath); } + else + path = (unsigned char *) strdup((char *) uripath); - if(!md5this) - return CURLE_OUT_OF_MEMORY; - - CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */ - Curl_md5it(md5buf, md5this); - Curl_safefree(md5this); - md5_to_ascii(md5buf, ha2); - - if(d->qop) { - md5this = (unsigned char *)aprintf("%s:%s:%08x:%s:%s:%s", - ha1, - d->nonce, - d->nc, - d->cnonce, - d->qop, - ha2); - } - else { - md5this = (unsigned char *)aprintf("%s:%s:%s", - ha1, - d->nonce, - ha2); - } - if(!md5this) + if(!path) return CURLE_OUT_OF_MEMORY; - CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */ - Curl_md5it(md5buf, md5this); - Curl_safefree(md5this); - md5_to_ascii(md5buf, request_digest); - - /* for test case 64 (snooped from a Mozilla 1.3a request) - - Authorization: Digest username="testuser", realm="testrealm", \ - nonce="1053604145", uri="/64", response="c55f7f30d83d774a3d2dcacf725abaca" - - Digest parameters are all quoted strings. Username which is provided by - the user will need double quotes and backslashes within it escaped. For - the other fields, this shouldn't be an issue. realm, nonce, and opaque - are copied as is from the server, escapes and all. cnonce is generated - with web-safe characters. uri is already percent encoded. nc is 8 hex - characters. algorithm and qop with standard values only contain web-safe - chracters. - */ - userp_quoted = string_quoted(userp); - if(!userp_quoted) - return CURLE_OUT_OF_MEMORY; + result = Curl_sasl_create_digest_http_message(data, userp, passwdp, request, + path, digest, &response, &len); + free(path); + if(result) + return result; - if(d->qop) { - *allocuserpwd = - aprintf( "%sAuthorization: Digest " - "username=\"%s\", " - "realm=\"%s\", " - "nonce=\"%s\", " - "uri=\"%.*s\", " - "cnonce=\"%s\", " - "nc=%08x, " - "qop=%s, " - "response=\"%s\"", - proxy?"Proxy-":"", - userp_quoted, - d->realm, - d->nonce, - urilen, uripath, /* this is the PATH part of the URL */ - d->cnonce, - d->nc, - d->qop, - request_digest); - - if(Curl_raw_equal(d->qop, "auth")) - d->nc++; /* The nc (from RFC) has to be a 8 hex digit number 0 padded - which tells to the server how many times you are using the - same nonce in the qop=auth mode. */ - } - else { - *allocuserpwd = - aprintf( "%sAuthorization: Digest " - "username=\"%s\", " - "realm=\"%s\", " - "nonce=\"%s\", " - "uri=\"%.*s\", " - "response=\"%s\"", - proxy?"Proxy-":"", - userp_quoted, - d->realm, - d->nonce, - urilen, uripath, /* this is the PATH part of the URL */ - request_digest); - } - Curl_safefree(userp_quoted); + *allocuserpwd = aprintf("%sAuthorization: Digest %s\r\n", + proxy ? "Proxy-" : "", + response); + free(response); if(!*allocuserpwd) return CURLE_OUT_OF_MEMORY; - /* Add optional fields */ - if(d->opaque) { - /* append opaque */ - tmp = aprintf("%s, opaque=\"%s\"", *allocuserpwd, d->opaque); - if(!tmp) - return CURLE_OUT_OF_MEMORY; - free(*allocuserpwd); - *allocuserpwd = tmp; - } - - if(d->algorithm) { - /* append algorithm */ - tmp = aprintf("%s, algorithm=\"%s\"", *allocuserpwd, d->algorithm); - if(!tmp) - return CURLE_OUT_OF_MEMORY; - free(*allocuserpwd); - *allocuserpwd = tmp; - } - - /* append CRLF + zero (3 bytes) to the userpwd header */ - userlen = strlen(*allocuserpwd); - tmp = realloc(*allocuserpwd, userlen + 3); - if(!tmp) - return CURLE_OUT_OF_MEMORY; - strcpy(&tmp[userlen], "\r\n"); /* append the data */ - *allocuserpwd = tmp; + authp->done = TRUE; return CURLE_OK; } -static void digest_cleanup_one(struct digestdata *d) -{ - Curl_safefree(d->nonce); - Curl_safefree(d->cnonce); - Curl_safefree(d->realm); - Curl_safefree(d->opaque); - Curl_safefree(d->qop); - Curl_safefree(d->algorithm); - - d->nc = 0; - d->algo = CURLDIGESTALGO_MD5; /* default algorithm */ - d->stale = FALSE; /* default means normal, not stale */ -} - - void Curl_digest_cleanup(struct SessionHandle *data) { - digest_cleanup_one(&data->state.digest); - digest_cleanup_one(&data->state.proxydigest); + Curl_sasl_digest_cleanup(&data->state.digest); + Curl_sasl_digest_cleanup(&data->state.proxydigest); } #endif diff --git a/Utilities/cmcurl/lib/http_digest.h b/Utilities/cmcurl/lib/http_digest.h index c6a4e91..d13d563 100644 --- a/Utilities/cmcurl/lib/http_digest.h +++ b/Utilities/cmcurl/lib/http_digest.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -23,24 +23,9 @@ ***************************************************************************/ #include "curl_setup.h" -typedef enum { - CURLDIGEST_NONE, /* not a digest */ - CURLDIGEST_BAD, /* a digest, but one we don't like */ - CURLDIGEST_BADALGO, /* unsupported algorithm requested */ - CURLDIGEST_NOMEM, - CURLDIGEST_FINE, /* a digest we act on */ - - CURLDIGEST_LAST /* last entry in this enum, don't use */ -} CURLdigest; - -enum { - CURLDIGESTALGO_MD5, - CURLDIGESTALGO_MD5SESS -}; - /* this is for digest header input */ -CURLdigest Curl_input_digest(struct connectdata *conn, - bool proxy, const char *header); +CURLcode Curl_input_digest(struct connectdata *conn, + bool proxy, const char *header); /* this is for creating digest header output */ CURLcode Curl_output_digest(struct connectdata *conn, diff --git a/Utilities/cmcurl/lib/http_negotiate.c b/Utilities/cmcurl/lib/http_negotiate.c index c8bfa29..a1baf29 100644 --- a/Utilities/cmcurl/lib/http_negotiate.c +++ b/Utilities/cmcurl/lib/http_negotiate.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -22,13 +22,7 @@ #include "curl_setup.h" -#ifdef HAVE_GSSAPI -#ifdef HAVE_OLD_GSSMIT -#define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name -#define NCOMPAT 1 -#endif - -#ifndef CURL_DISABLE_HTTP +#if defined(HAVE_GSSAPI) && !defined(CURL_DISABLE_HTTP) && defined(USE_SPNEGO) #include "urldata.h" #include "sendf.h" @@ -36,97 +30,63 @@ #include "rawstr.h" #include "curl_base64.h" #include "http_negotiate.h" -#include "curl_memory.h" +#include "curl_sasl.h" #include "url.h" +#include "curl_printf.h" -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - -/* The last #include file should be: */ +/* The last #include files should be: */ +#include "curl_memory.h" #include "memdebug.h" -static int -get_gss_name(struct connectdata *conn, bool proxy, gss_name_t *server) -{ - OM_uint32 major_status, minor_status; - gss_buffer_desc token = GSS_C_EMPTY_BUFFER; - char name[2048]; - const char* service = "HTTP"; - - token.length = strlen(service) + 1 + strlen(proxy ? conn->proxy.name : - conn->host.name) + 1; - if(token.length + 1 > sizeof(name)) - return EMSGSIZE; - - snprintf(name, sizeof(name), "%s@%s", service, proxy ? conn->proxy.name : - conn->host.name); - - token.value = (void *) name; - major_status = gss_import_name(&minor_status, - &token, - GSS_C_NT_HOSTBASED_SERVICE, - server); - - return GSS_ERROR(major_status) ? -1 : 0; -} - -static void -log_gss_error(struct connectdata *conn, OM_uint32 error_status, - const char *prefix) -{ - OM_uint32 maj_stat, min_stat; - OM_uint32 msg_ctx = 0; - gss_buffer_desc status_string; - char buf[1024]; - size_t len; - - snprintf(buf, sizeof(buf), "%s", prefix); - len = strlen(buf); - do { - maj_stat = gss_display_status(&min_stat, - error_status, - GSS_C_MECH_CODE, - GSS_C_NO_OID, - &msg_ctx, - &status_string); - if(sizeof(buf) > len + status_string.length + 1) { - snprintf(buf + len, sizeof(buf) - len, - ": %s", (char*) status_string.value); - len += status_string.length; - } - gss_release_buffer(&min_stat, &status_string); - } while(!GSS_ERROR(maj_stat) && msg_ctx != 0); - - infof(conn->data, "%s\n", buf); -} - -/* returning zero (0) means success, everything else is treated as "failure" - with no care exactly what the failure was */ -int Curl_input_negotiate(struct connectdata *conn, bool proxy, - const char *header) +CURLcode Curl_input_negotiate(struct connectdata *conn, bool proxy, + const char *header) { struct SessionHandle *data = conn->data; struct negotiatedata *neg_ctx = proxy?&data->state.proxyneg: &data->state.negotiate; OM_uint32 major_status, minor_status, discard_st; + gss_buffer_desc spn_token = GSS_C_EMPTY_BUFFER; gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; - int ret; size_t len; size_t rawlen = 0; - CURLcode error; + CURLcode result; if(neg_ctx->context && neg_ctx->status == GSS_S_COMPLETE) { /* We finished successfully our part of authentication, but server * rejected it (since we're again here). Exit with an error since we * can't invent anything better */ Curl_cleanup_negotiate(data); - return -1; + return CURLE_LOGIN_DENIED; } - if(neg_ctx->server_name == NULL && - (ret = get_gss_name(conn, proxy, &neg_ctx->server_name))) - return ret; + if(!neg_ctx->server_name) { + /* Generate our SPN */ + char *spn = Curl_sasl_build_gssapi_spn( + proxy ? data->set.str[STRING_PROXY_SERVICE_NAME] : + data->set.str[STRING_SERVICE_NAME], + proxy ? conn->proxy.name : conn->host.name); + if(!spn) + return CURLE_OUT_OF_MEMORY; + + /* Populate the SPN structure */ + spn_token.value = spn; + spn_token.length = strlen(spn); + + /* Import the SPN */ + major_status = gss_import_name(&minor_status, &spn_token, + GSS_C_NT_HOSTBASED_SERVICE, + &neg_ctx->server_name); + if(GSS_ERROR(major_status)) { + Curl_gss_log_error(data, minor_status, "gss_import_name() failed: "); + + free(spn); + + return CURLE_OUT_OF_MEMORY; + } + + free(spn); + } header += strlen("Negotiate"); while(*header && ISSPACE(*header)) @@ -134,10 +94,17 @@ int Curl_input_negotiate(struct connectdata *conn, bool proxy, len = strlen(header); if(len > 0) { - error = Curl_base64_decode(header, - (unsigned char **)&input_token.value, &rawlen); - if(error || rawlen == 0) - return -1; + result = Curl_base64_decode(header, (unsigned char **)&input_token.value, + &rawlen); + if(result) + return result; + + if(!rawlen) { + infof(data, "Negotiate handshake failure (empty challenge message)\n"); + + return CURLE_BAD_CONTENT_ENCODING; + } + input_token.length = rawlen; DEBUGASSERT(input_token.value != NULL); @@ -151,6 +118,7 @@ int Curl_input_negotiate(struct connectdata *conn, bool proxy, GSS_C_NO_CHANNEL_BINDINGS, &input_token, &output_token, + TRUE, NULL); Curl_safefree(input_token.value); @@ -158,20 +126,21 @@ int Curl_input_negotiate(struct connectdata *conn, bool proxy, if(GSS_ERROR(major_status)) { if(output_token.value) gss_release_buffer(&discard_st, &output_token); - log_gss_error(conn, minor_status, "gss_init_sec_context() failed: "); - return -1; + Curl_gss_log_error(conn->data, minor_status, + "gss_init_sec_context() failed: "); + return CURLE_OUT_OF_MEMORY; } if(!output_token.value || !output_token.length) { if(output_token.value) gss_release_buffer(&discard_st, &output_token); - return -1; + return CURLE_OUT_OF_MEMORY; } neg_ctx->output_token = output_token; - return 0; -} + return CURLE_OK; +} CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy) { @@ -180,18 +149,18 @@ CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy) char *encoded = NULL; size_t len = 0; char *userp; - CURLcode error; + CURLcode result; OM_uint32 discard_st; - error = Curl_base64_encode(conn->data, - neg_ctx->output_token.value, - neg_ctx->output_token.length, - &encoded, &len); - if(error) { + result = Curl_base64_encode(conn->data, + neg_ctx->output_token.value, + neg_ctx->output_token.length, + &encoded, &len); + if(result) { gss_release_buffer(&discard_st, &neg_ctx->output_token); neg_ctx->output_token.value = NULL; neg_ctx->output_token.length = 0; - return error; + return result; } if(!encoded || !len) { @@ -212,7 +181,7 @@ CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy) conn->allocptr.userpwd = userp; } - Curl_safefree(encoded); + free(encoded); return (userp == NULL) ? CURLE_OUT_OF_MEMORY : CURLE_OK; } @@ -238,6 +207,4 @@ void Curl_cleanup_negotiate(struct SessionHandle *data) cleanup(&data->state.proxyneg); } - -#endif -#endif +#endif /* HAVE_GSSAPI && !CURL_DISABLE_HTTP && USE_SPNEGO */ diff --git a/Utilities/cmcurl/lib/http_negotiate.h b/Utilities/cmcurl/lib/http_negotiate.h index f7efe8c..a8eb980 100644 --- a/Utilities/cmcurl/lib/http_negotiate.h +++ b/Utilities/cmcurl/lib/http_negotiate.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -25,8 +25,8 @@ #ifdef USE_SPNEGO /* this is for Negotiate header input */ -int Curl_input_negotiate(struct connectdata *conn, bool proxy, - const char *header); +CURLcode Curl_input_negotiate(struct connectdata *conn, bool proxy, + const char *header); /* this is for creating Negotiate header output */ CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy); diff --git a/Utilities/cmcurl/lib/http_negotiate_sspi.c b/Utilities/cmcurl/lib/http_negotiate_sspi.c index 61581f1..a50ea96 100644 --- a/Utilities/cmcurl/lib/http_negotiate_sspi.c +++ b/Utilities/cmcurl/lib/http_negotiate_sspi.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -33,30 +33,27 @@ #include "curl_base64.h" #include "curl_sasl.h" #include "http_negotiate.h" -#include "curl_memory.h" #include "curl_multibyte.h" +#include "curl_printf.h" -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - -/* The last #include file should be: */ +/* The last #include files should be: */ +#include "curl_memory.h" #include "memdebug.h" -/* returning zero (0) means success, everything else is treated as "failure" - with no care exactly what the failure was */ -int Curl_input_negotiate(struct connectdata *conn, bool proxy, - const char *header) +CURLcode Curl_input_negotiate(struct connectdata *conn, bool proxy, + const char *header) { + struct SessionHandle *data = conn->data; BYTE *input_token = NULL; SecBufferDesc out_buff_desc; SecBuffer out_sec_buff; SecBufferDesc in_buff_desc; SecBuffer in_sec_buff; - unsigned long context_attributes; - TimeStamp lifetime; - int ret; + SECURITY_STATUS status; + unsigned long attrs; + TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ size_t len = 0, input_token_len = 0; - CURLcode error; + CURLcode result; /* Point to the username and password */ const char *userp; @@ -68,12 +65,12 @@ int Curl_input_negotiate(struct connectdata *conn, bool proxy, if(proxy) { userp = conn->proxyuser; passwdp = conn->proxypasswd; - neg_ctx = &conn->data->state.proxyneg; + neg_ctx = &data->state.proxyneg; } else { userp = conn->user; passwdp = conn->passwd; - neg_ctx = &conn->data->state.negotiate; + neg_ctx = &data->state.negotiate; } /* Not set means empty */ @@ -87,34 +84,36 @@ int Curl_input_negotiate(struct connectdata *conn, bool proxy, /* We finished successfully our part of authentication, but server * rejected it (since we're again here). Exit with an error since we * can't invent anything better */ - Curl_cleanup_negotiate(conn->data); - return -1; + Curl_cleanup_negotiate(data); + return CURLE_LOGIN_DENIED; } if(!neg_ctx->server_name) { /* Check proxy auth requested but no given proxy name */ if(proxy && !conn->proxy.name) - return -1; + return CURLE_BAD_FUNCTION_ARGUMENT; /* Generate our SPN */ - neg_ctx->server_name = Curl_sasl_build_spn("HTTP", - proxy ? conn->proxy.name : - conn->host.name); + neg_ctx->server_name = Curl_sasl_build_spn( + proxy ? data->set.str[STRING_PROXY_SERVICE_NAME] : + data->set.str[STRING_SERVICE_NAME], + proxy ? conn->proxy.name : conn->host.name); if(!neg_ctx->server_name) - return -1; + return CURLE_OUT_OF_MEMORY; } if(!neg_ctx->output_token) { PSecPkgInfo SecurityPackage; - ret = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT("Negotiate"), - &SecurityPackage); - if(ret != SEC_E_OK) - return -1; + status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) + TEXT(SP_NAME_NEGOTIATE), + &SecurityPackage); + if(status != SEC_E_OK) + return CURLE_NOT_BUILT_IN; /* Allocate input and output buffers according to the max token size as indicated by the security package */ - neg_ctx->max_token_length = SecurityPackage->cbMaxToken; - neg_ctx->output_token = malloc(neg_ctx->max_token_length); + neg_ctx->token_max = SecurityPackage->cbMaxToken; + neg_ctx->output_token = malloc(neg_ctx->token_max); s_pSecFn->FreeContextBuffer(SecurityPackage); } @@ -129,7 +128,7 @@ int Curl_input_negotiate(struct connectdata *conn, bool proxy, if(neg_ctx->context) { /* The server rejected our authentication and hasn't suppled any more negotiation mechanisms */ - return -1; + return CURLE_LOGIN_DENIED; } /* We have to acquire credentials and allocate memory for the context */ @@ -137,13 +136,13 @@ int Curl_input_negotiate(struct connectdata *conn, bool proxy, neg_ctx->context = malloc(sizeof(CtxtHandle)); if(!neg_ctx->credentials || !neg_ctx->context) - return -1; + return CURLE_OUT_OF_MEMORY; if(userp && *userp) { /* Populate our identity structure */ - error = Curl_create_sspi_identity(userp, passwdp, &neg_ctx->identity); - if(error) - return -1; + result = Curl_create_sspi_identity(userp, passwdp, &neg_ctx->identity); + if(result) + return result; /* Allow proper cleanup of the identity structure */ neg_ctx->p_identity = &neg_ctx->identity; @@ -155,19 +154,26 @@ int Curl_input_negotiate(struct connectdata *conn, bool proxy, /* Acquire our credientials handle */ neg_ctx->status = s_pSecFn->AcquireCredentialsHandle(NULL, - (TCHAR *) TEXT("Negotiate"), + (TCHAR *) TEXT(SP_NAME_NEGOTIATE), SECPKG_CRED_OUTBOUND, NULL, neg_ctx->p_identity, NULL, NULL, - neg_ctx->credentials, &lifetime); + neg_ctx->credentials, &expiry); if(neg_ctx->status != SEC_E_OK) - return -1; + return CURLE_LOGIN_DENIED; } else { - error = Curl_base64_decode(header, - (unsigned char **)&input_token, - &input_token_len); - if(error || !input_token_len) - return -1; + result = Curl_base64_decode(header, + (unsigned char **)&input_token, + &input_token_len); + if(result) + return result; + + if(!input_token_len) { + infof(data, + "Negotiate handshake failure (empty challenge message)\n"); + + return CURLE_BAD_CONTENT_ENCODING; + } } /* Setup the "output" security buffer */ @@ -176,7 +182,7 @@ int Curl_input_negotiate(struct connectdata *conn, bool proxy, out_buff_desc.pBuffers = &out_sec_buff; out_sec_buff.BufferType = SECBUFFER_TOKEN; out_sec_buff.pvBuffer = neg_ctx->output_token; - out_sec_buff.cbBuffer = curlx_uztoul(neg_ctx->max_token_length); + out_sec_buff.cbBuffer = curlx_uztoul(neg_ctx->token_max); /* Setup the "input" security buffer if present */ if(input_token) { @@ -200,28 +206,27 @@ int Curl_input_negotiate(struct connectdata *conn, bool proxy, 0, neg_ctx->context, &out_buff_desc, - &context_attributes, - &lifetime); + &attrs, + &expiry); - Curl_safefree(input_token); + free(input_token); if(GSS_ERROR(neg_ctx->status)) - return -1; + return CURLE_OUT_OF_MEMORY; if(neg_ctx->status == SEC_I_COMPLETE_NEEDED || neg_ctx->status == SEC_I_COMPLETE_AND_CONTINUE) { neg_ctx->status = s_pSecFn->CompleteAuthToken(neg_ctx->context, &out_buff_desc); if(GSS_ERROR(neg_ctx->status)) - return -1; + return CURLE_RECV_ERROR; } neg_ctx->output_token_length = out_sec_buff.cbBuffer; - return 0; + return CURLE_OK; } - CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy) { struct negotiatedata *neg_ctx = proxy?&conn->data->state.proxyneg: @@ -258,25 +263,30 @@ CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy) static void cleanup(struct negotiatedata *neg_ctx) { + /* Free our security context */ if(neg_ctx->context) { s_pSecFn->DeleteSecurityContext(neg_ctx->context); free(neg_ctx->context); neg_ctx->context = NULL; } + /* Free our credentials handle */ if(neg_ctx->credentials) { s_pSecFn->FreeCredentialsHandle(neg_ctx->credentials); free(neg_ctx->credentials); neg_ctx->credentials = NULL; } - neg_ctx->max_token_length = 0; - Curl_safefree(neg_ctx->output_token); + /* Free our identity */ + Curl_sspi_free_identity(neg_ctx->p_identity); + neg_ctx->p_identity = NULL; + /* Free the SPN and output token */ Curl_safefree(neg_ctx->server_name); + Curl_safefree(neg_ctx->output_token); - Curl_sspi_free_identity(neg_ctx->p_identity); - neg_ctx->p_identity = NULL; + /* Reset any variables */ + neg_ctx->token_max = 0; } void Curl_cleanup_negotiate(struct SessionHandle *data) diff --git a/Utilities/cmcurl/lib/http_proxy.c b/Utilities/cmcurl/lib/http_proxy.c index 5343eb7..4373d62 100644 --- a/Utilities/cmcurl/lib/http_proxy.c +++ b/Utilities/cmcurl/lib/http_proxy.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -35,10 +35,7 @@ #include "progress.h" #include "non-ascii.h" #include "connect.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - +#include "curl_printf.h" #include "curlx.h" #include "curl_memory.h" @@ -71,10 +68,11 @@ CURLcode Curl_proxy_connect(struct connectdata *conn) conn->data->req.protop = &http_proxy; connkeep(conn, "HTTP proxy CONNECT"); result = Curl_proxyCONNECT(conn, FIRSTSOCKET, - conn->host.name, conn->remote_port); + conn->host.name, conn->remote_port, FALSE); conn->data->req.protop = prot_save; if(CURLE_OK != result) return result; + Curl_safefree(conn->allocptr.proxyuserpwd); #else return CURLE_NOT_BUILT_IN; #endif @@ -87,12 +85,16 @@ CURLcode Curl_proxy_connect(struct connectdata *conn) * Curl_proxyCONNECT() requires that we're connected to a HTTP proxy. This * function will issue the necessary commands to get a seamless tunnel through * this proxy. After that, the socket can be used just as a normal socket. + * + * 'blocking' set to TRUE means that this function will do the entire CONNECT + * + response in a blocking fashion. Should be avoided! */ CURLcode Curl_proxyCONNECT(struct connectdata *conn, int sockindex, const char *hostname, - int remote_port) + int remote_port, + bool blocking) { int subversion=0; struct SessionHandle *data=conn->data; @@ -123,13 +125,11 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, infof(data, "Establish HTTP proxy tunnel to %s:%hu\n", hostname, remote_port); - if(data->req.newurl) { /* This only happens if we've looped here due to authentication reasons, and we don't really use the newly cloned URL here then. Just free() it. */ - free(data->req.newurl); - data->req.newurl = NULL; - } + free(data->req.newurl); + data->req.newurl = NULL; /* initialize a dynamic send-buffer */ req_buffer = Curl_add_buffer_init(); @@ -139,7 +139,7 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, host_port = aprintf("%s:%hu", hostname, remote_port); if(!host_port) { - free(req_buffer); + Curl_add_buffer_free(req_buffer); return CURLE_OUT_OF_MEMORY; } @@ -148,7 +148,7 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, free(host_port); - if(CURLE_OK == result) { + if(!result) { char *host=(char *)""; const char *proxyconn=""; const char *useragent=""; @@ -159,7 +159,7 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, hostname, conn->bits.ipv6_ip?"]":"", remote_port); if(!hostheader) { - free(req_buffer); + Curl_add_buffer_free(req_buffer); return CURLE_OUT_OF_MEMORY; } @@ -167,7 +167,7 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, host = aprintf("Host: %s\r\n", hostheader); if(!host) { free(hostheader); - free(req_buffer); + Curl_add_buffer_free(req_buffer); return CURLE_OUT_OF_MEMORY; } } @@ -197,14 +197,14 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, free(host); free(hostheader); - if(CURLE_OK == result) + if(!result) result = Curl_add_custom_headers(conn, TRUE, req_buffer); - if(CURLE_OK == result) + if(!result) /* CRLF terminate the request */ result = Curl_add_bufferf(req_buffer, "\r\n"); - if(CURLE_OK == result) { + if(!result) { /* Send the connect request to the proxy */ /* BLOCKING */ result = @@ -216,7 +216,7 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, failf(data, "Failed sending CONNECT to proxy"); } - Curl_safefree(req_buffer); + Curl_add_buffer_free(req_buffer); if(result) return result; @@ -229,12 +229,14 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, return CURLE_RECV_ERROR; } - if(0 == Curl_socket_ready(tunnelsocket, CURL_SOCKET_BAD, 0)) - /* return so we'll be called again polling-style */ - return CURLE_OK; - else { - DEBUGF(infof(data, - "Read response immediately from proxy CONNECT\n")); + if(!blocking) { + if(0 == Curl_socket_ready(tunnelsocket, CURL_SOCKET_BAD, 0)) + /* return so we'll be called again polling-style */ + return CURLE_OK; + else { + DEBUGF(infof(data, + "Read response immediately from proxy CONNECT\n")); + } } /* at this point, the tunnel_connecting phase is over. */ @@ -252,7 +254,6 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, nread=0; perline=0; - keepon=TRUE; while((nread<BUFSIZE) && (keepon && !error)) { @@ -286,7 +287,7 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, /* proxy auth was requested and there was proxy auth available, then deem this as "mere" proxy disconnect */ conn->bits.proxy_connect_closed = TRUE; - infof(data, "Proxy CONNECT connection closed"); + infof(data, "Proxy CONNECT connection closed\n"); } else { error = SELECT_ERROR; @@ -468,7 +469,7 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, result = Curl_http_input_auth(conn, proxy, auth); - Curl_safefree(auth); + free(auth); if(result) return result; @@ -555,11 +556,8 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, infof(data, "Connect me again please\n"); } else { - if(data->req.newurl) { - /* this won't be used anymore for the CONNECT so free it now */ - free(data->req.newurl); - data->req.newurl = NULL; - } + free(data->req.newurl); + data->req.newurl = NULL; /* failure, close this connection to avoid re-use */ connclose(conn, "proxy CONNECT failure"); Curl_closesocket(conn, conn->sock[sockindex]); diff --git a/Utilities/cmcurl/lib/http_proxy.h b/Utilities/cmcurl/lib/http_proxy.h index 2b5e9c9..9c4f020 100644 --- a/Utilities/cmcurl/lib/http_proxy.h +++ b/Utilities/cmcurl/lib/http_proxy.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -26,7 +26,8 @@ /* ftp can use this as well */ CURLcode Curl_proxyCONNECT(struct connectdata *conn, int tunnelsocket, - const char *hostname, int remote_port); + const char *hostname, int remote_port, + bool blocking); /* Default proxy timeout in milliseconds */ #define PROXY_TIMEOUT (3600*1000) @@ -34,7 +35,7 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, CURLcode Curl_proxy_connect(struct connectdata *conn); #else -#define Curl_proxyCONNECT(x,y,z,w) CURLE_NOT_BUILT_IN +#define Curl_proxyCONNECT(x,y,z,w,v) CURLE_NOT_BUILT_IN #define Curl_proxy_connect(x) CURLE_OK #endif diff --git a/Utilities/cmcurl/lib/idn_win32.c b/Utilities/cmcurl/lib/idn_win32.c index 464964b..b369723 100644 --- a/Utilities/cmcurl/lib/idn_win32.c +++ b/Utilities/cmcurl/lib/idn_win32.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -35,8 +35,31 @@ #include "memdebug.h" #ifdef WANT_IDN_PROTOTYPES -WINBASEAPI int WINAPI IdnToAscii(DWORD, const WCHAR *, int, WCHAR *, int); -WINBASEAPI int WINAPI IdnToUnicode(DWORD, const WCHAR *, int, WCHAR *, int); +# if defined(_SAL_VERSION) +WINNORMALIZEAPI int WINAPI +IdnToAscii(_In_ DWORD dwFlags, + _In_reads_(cchUnicodeChar) LPCWSTR lpUnicodeCharStr, + _In_ int cchUnicodeChar, + _Out_writes_opt_(cchASCIIChar) LPWSTR lpASCIICharStr, + _In_ int cchASCIIChar); +WINNORMALIZEAPI int WINAPI +IdnToUnicode(_In_ DWORD dwFlags, + _In_reads_(cchASCIIChar) LPCWSTR lpASCIICharStr, + _In_ int cchASCIIChar, + _Out_writes_opt_(cchUnicodeChar) LPWSTR lpUnicodeCharStr, + _In_ int cchUnicodeChar); +# else +WINBASEAPI int WINAPI IdnToAscii(DWORD dwFlags, + const WCHAR *lpUnicodeCharStr, + int cchUnicodeChar, + WCHAR *lpASCIICharStr, + int cchASCIIChar); +WINBASEAPI int WINAPI IdnToUnicode(DWORD dwFlags, + const WCHAR *lpASCIICharStr, + int cchASCIIChar, + WCHAR *lpUnicodeCharStr, + int cchUnicodeChar); +# endif #endif #define IDN_MAX_LENGTH 255 diff --git a/Utilities/cmcurl/lib/if2ip.c b/Utilities/cmcurl/lib/if2ip.c index 05ae7d6..6e6f969 100644 --- a/Utilities/cmcurl/lib/if2ip.c +++ b/Utilities/cmcurl/lib/if2ip.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -53,9 +53,7 @@ #include "inet_ntop.h" #include "strequal.h" #include "if2ip.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> +#include "curl_printf.h" #include "curl_memory.h" /* The last #include file should be: */ @@ -63,6 +61,38 @@ /* ------------------------------------------------------------------ */ +/* Return the scope of the given address. */ +unsigned int Curl_ipv6_scope(const struct sockaddr *sa) +{ +#ifndef ENABLE_IPV6 + (void) sa; +#else + if(sa->sa_family == AF_INET6) { + const struct sockaddr_in6 * sa6 = (const struct sockaddr_in6 *) sa; + const unsigned char * b = sa6->sin6_addr.s6_addr; + unsigned short w = (unsigned short) ((b[0] << 8) | b[1]); + + switch(w & 0xFFC0) { + case 0xFE80: + return IPV6_SCOPE_LINKLOCAL; + case 0xFEC0: + return IPV6_SCOPE_SITELOCAL; + case 0x0000: + w = b[1] | b[2] | b[3] | b[4] | b[5] | b[6] | b[7] | b[8] | b[9] | + b[10] | b[11] | b[12] | b[13] | b[14]; + if(w || b[15] != 0x01) + break; + return IPV6_SCOPE_NODELOCAL; + default: + break; + } + } +#endif + + return IPV6_SCOPE_GLOBAL; +} + + #if defined(HAVE_GETIFADDRS) bool Curl_if_is_interface_name(const char *interf) @@ -84,41 +114,58 @@ bool Curl_if_is_interface_name(const char *interf) } if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope, - const char *interf, char *buf, int buf_size) + unsigned int remote_scope_id, const char *interf, + char *buf, int buf_size) { struct ifaddrs *iface, *head; if2ip_result_t res = IF2IP_NOT_FOUND; #ifndef ENABLE_IPV6 (void) remote_scope; + +#ifndef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID + (void) remote_scope_id; +#endif + #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(curl_strequal(iface->ifa_name, interf)) { void *addr; char *ip; - char scope[12]=""; + char scope[12] = ""; char ipstr[64]; #ifdef ENABLE_IPV6 if(af == AF_INET6) { unsigned int scopeid = 0; + unsigned int ifscope = Curl_ipv6_scope(iface->ifa_addr); + + if(ifscope != remote_scope) { + /* We are interested only in interface addresses whose + scope matches the remote address we want to + connect to: global for global, link-local for + link-local, etc... */ + if(res == IF2IP_NOT_FOUND) res = IF2IP_AF_NOT_SUPPORTED; + continue; + } + addr = &((struct sockaddr_in6 *)iface->ifa_addr)->sin6_addr; #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID /* Include the scope of this interface as part of the address */ scopeid = ((struct sockaddr_in6 *)iface->ifa_addr)->sin6_scope_id; -#endif - if(scopeid != remote_scope) { - /* We are interested only in interface addresses whose - scope ID matches the remote address we want to - connect to: global (0) for global, link-local for - link-local, etc... */ - if(res == IF2IP_NOT_FOUND) res = IF2IP_AF_NOT_SUPPORTED; + + /* If given, scope id should match. */ + if(remote_scope_id && scopeid != remote_scope_id) { + if(res == IF2IP_NOT_FOUND) + res = IF2IP_AF_NOT_SUPPORTED; + continue; } +#endif if(scopeid) snprintf(scope, sizeof(scope), "%%%u", scopeid); } @@ -137,8 +184,10 @@ if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope, } } } + freeifaddrs(head); } + return res; } @@ -149,12 +198,13 @@ bool Curl_if_is_interface_name(const char *interf) /* This is here just to support the old interfaces */ char buf[256]; - return (Curl_if2ip(AF_INET, 0, interf, buf, sizeof(buf)) == + return (Curl_if2ip(AF_INET, 0 /* unused */, 0, interf, buf, sizeof(buf)) == IF2IP_NOT_FOUND) ? FALSE : TRUE; } if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope, - const char *interf, char *buf, int buf_size) + unsigned int remote_scope_id, const char *interf, + char *buf, int buf_size) { struct ifreq req; struct in_addr in; @@ -163,6 +213,7 @@ if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope, size_t len; (void)remote_scope; + (void)remote_scope_id; if(!interf || (af != AF_INET)) return IF2IP_NOT_FOUND; @@ -205,10 +256,12 @@ bool Curl_if_is_interface_name(const char *interf) } if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope, - const char *interf, char *buf, int buf_size) + unsigned int remote_scope_id, const char *interf, + char *buf, int buf_size) { (void) af; (void) remote_scope; + (void) remote_scope_id; (void) interf; (void) buf; (void) buf_size; diff --git a/Utilities/cmcurl/lib/if2ip.h b/Utilities/cmcurl/lib/if2ip.h index ac58752..78bb0bd 100644 --- a/Utilities/cmcurl/lib/if2ip.h +++ b/Utilities/cmcurl/lib/if2ip.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -23,6 +23,14 @@ ***************************************************************************/ #include "curl_setup.h" +/* IPv6 address scopes. */ +#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. */ + +unsigned int Curl_ipv6_scope(const struct sockaddr *sa); + bool Curl_if_is_interface_name(const char *interf); typedef enum { @@ -32,7 +40,8 @@ typedef enum { } if2ip_result_t; if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope, - const char *interf, char *buf, int buf_size); + unsigned int remote_scope_id, const char *interf, + char *buf, int buf_size); #ifdef __INTERIX diff --git a/Utilities/cmcurl/lib/imap.c b/Utilities/cmcurl/lib/imap.c index 9fc4728..e6d83f2 100644 --- a/Utilities/cmcurl/lib/imap.c +++ b/Utilities/cmcurl/lib/imap.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -61,7 +61,6 @@ #include <curl/curl.h> #include "urldata.h" #include "sendf.h" -#include "if2ip.h" #include "hostip.h" #include "progress.h" #include "transfer.h" @@ -81,9 +80,7 @@ #include "rawstr.h" #include "curl_sasl.h" #include "warnless.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> +#include "curl_printf.h" #include "curl_memory.h" /* The last #include file should be: */ @@ -106,10 +103,12 @@ static CURLcode imap_sendf(struct connectdata *conn, const char *fmt, ...); static CURLcode imap_parse_url_options(struct connectdata *conn); static CURLcode imap_parse_url_path(struct connectdata *conn); static CURLcode imap_parse_custom_request(struct connectdata *conn); -static CURLcode imap_calc_sasl_details(struct connectdata *conn, - const char **mech, - char **initresp, size_t *len, - imapstate *state1, imapstate *state2); +static CURLcode imap_perform_authenticate(struct connectdata *conn, + const char *mech, + const char *initresp); +static CURLcode imap_continue_authenticate(struct connectdata *conn, + const char *resp); +static void imap_get_message(char *buffer, char** outptr); /* * IMAP protocol handler. @@ -132,7 +131,7 @@ const struct Curl_handler Curl_handler_imap = { ZERO_NULL, /* readwrite */ PORT_IMAP, /* defport */ CURLPROTO_IMAP, /* protocol */ - PROTOPT_CLOSEACTION | PROTOPT_NEEDSPWD /* flags */ + PROTOPT_CLOSEACTION /* flags */ }; #ifdef USE_SSL @@ -157,8 +156,7 @@ const struct Curl_handler Curl_handler_imaps = { ZERO_NULL, /* readwrite */ PORT_IMAPS, /* defport */ CURLPROTO_IMAPS, /* protocol */ - PROTOPT_CLOSEACTION | PROTOPT_SSL | - PROTOPT_NEEDSPWD /* flags */ + PROTOPT_CLOSEACTION | PROTOPT_SSL /* flags */ }; #endif @@ -214,6 +212,18 @@ static const struct Curl_handler Curl_handler_imaps_proxy = { #endif #endif +/* 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 */ + 0, /* Maximum initial response length (no max) */ + imap_perform_authenticate, /* Send authentication command */ + imap_continue_authenticate, /* Send authentication continuation */ + imap_get_message /* Get SASL response message */ +}; + + #ifdef USE_SSL static void imap_to_imaps(struct connectdata *conn) { @@ -354,16 +364,7 @@ static bool imap_endofresp(struct connectdata *conn, char *line, size_t len, (len >= 2 && !memcmp("+ ", line, 2))) { switch(imapc->state) { /* States which are interested in continuation responses */ - case IMAP_AUTHENTICATE_PLAIN: - case IMAP_AUTHENTICATE_LOGIN: - case IMAP_AUTHENTICATE_LOGIN_PASSWD: - case IMAP_AUTHENTICATE_CRAMMD5: - case IMAP_AUTHENTICATE_DIGESTMD5: - case IMAP_AUTHENTICATE_DIGESTMD5_RESP: - case IMAP_AUTHENTICATE_NTLM: - case IMAP_AUTHENTICATE_NTLM_TYPE2MSG: - case IMAP_AUTHENTICATE_XOAUTH2: - case IMAP_AUTHENTICATE_FINAL: + case IMAP_AUTHENTICATE: case IMAP_APPEND: *resp = '+'; break; @@ -426,20 +427,7 @@ static void state(struct connectdata *conn, imapstate newstate) "CAPABILITY", "STARTTLS", "UPGRADETLS", - "AUTHENTICATE_PLAIN", - "AUTHENTICATE_LOGIN", - "AUTHENTICATE_LOGIN_PASSWD", - "AUTHENTICATE_CRAMMD5", - "AUTHENTICATE_DIGESTMD5", - "AUTHENTICATE_DIGESTMD5_RESP", - "AUTHENTICATE_NTLM", - "AUTHENTICATE_NTLM_TYPE2MSG", - "AUTHENTICATE_GSSAPI", - "AUTHENTICATE_GSSAPI_TOKEN", - "AUTHENTICATE_GSSAPI_NO_DATA", - "AUTHENTICATE_XOAUTH2", - "AUTHENTICATE_CANCEL", - "AUTHENTICATE_FINAL", + "AUTHENTICATE", "LOGIN", "LIST", "SELECT", @@ -472,9 +460,9 @@ static CURLcode imap_perform_capability(struct connectdata *conn) CURLcode result = CURLE_OK; struct imap_conn *imapc = &conn->proto.imapc; - imapc->authmechs = 0; /* No known authentication mechanisms yet */ - imapc->authused = 0; /* Clear the authentication mechanism used */ - imapc->tls_supported = FALSE; /* Clear the TLS capability */ + imapc->sasl.authmechs = SASL_AUTH_NONE; /* No known auth. mechanisms yet */ + imapc->sasl.authused = SASL_AUTH_NONE; /* Clear the auth. mechanism used */ + imapc->tls_supported = FALSE; /* Clear the TLS capability */ /* Send the CAPABILITY command */ result = imap_sendf(conn, "CAPABILITY"); @@ -559,8 +547,8 @@ static CURLcode imap_perform_login(struct connectdata *conn) result = imap_sendf(conn, "LOGIN %s %s", user ? user : "", passwd ? passwd : ""); - Curl_safefree(user); - Curl_safefree(passwd); + free(user); + free(passwd); if(!result) state(conn, IMAP_LOGIN); @@ -577,24 +565,17 @@ static CURLcode imap_perform_login(struct connectdata *conn) */ static CURLcode imap_perform_authenticate(struct connectdata *conn, const char *mech, - const char *initresp, - imapstate state1, imapstate state2) + const char *initresp) { CURLcode result = CURLE_OK; if(initresp) { /* Send the AUTHENTICATE command with the initial response */ result = imap_sendf(conn, "AUTHENTICATE %s %s", mech, initresp); - - if(!result) - state(conn, state2); } else { /* Send the AUTHENTICATE command */ result = imap_sendf(conn, "AUTHENTICATE %s", mech); - - if(!result) - state(conn, state1); } return result; @@ -602,6 +583,20 @@ static CURLcode imap_perform_authenticate(struct connectdata *conn, /*********************************************************************** * + * imap_continue_authenticate() + * + * Sends SASL continuation data or cancellation. + */ +static CURLcode imap_continue_authenticate(struct connectdata *conn, + const char *resp) +{ + struct imap_conn *imapc = &conn->proto.imapc; + + return Curl_pp_sendf(&imapc->pp, "%s", resp); +} + +/*********************************************************************** + * * imap_perform_authentication() * * Initiates the authentication sequence, with the appropriate SASL @@ -612,33 +607,22 @@ static CURLcode imap_perform_authentication(struct connectdata *conn) { CURLcode result = CURLE_OK; struct imap_conn *imapc = &conn->proto.imapc; - const char *mech = NULL; - char *initresp = NULL; - size_t len = 0; - imapstate state1 = IMAP_STOP; - imapstate state2 = IMAP_STOP; + saslprogress progress; - /* Check we have a username and password to authenticate with and end the + /* Check we have enough data to authenticate with and end the connect phase if we don't */ - if(!conn->bits.user_passwd) { + if(!Curl_sasl_can_authenticate(&imapc->sasl, conn)) { state(conn, IMAP_STOP); - return result; } /* Calculate the SASL login details */ - result = imap_calc_sasl_details(conn, &mech, &initresp, &len, &state1, - &state2); + result = Curl_sasl_start(&imapc->sasl, conn, imapc->ir_supported, &progress); if(!result) { - if(mech && (imapc->preftype & IMAP_TYPE_SASL)) { - /* Perform SASL based authentication */ - result = imap_perform_authenticate(conn, mech, initresp, state1, state2); - - Curl_safefree(initresp); - } - else if((!imapc->login_disabled) && - (imapc->preftype & IMAP_TYPE_CLEARTEXT)) + if(progress == SASL_INPROGRESS) + state(conn, IMAP_AUTHENTICATE); + else if(!imapc->login_disabled && (imapc->preftype & IMAP_TYPE_CLEARTEXT)) /* Perform clear text authentication */ result = imap_perform_login(conn); else { @@ -677,7 +661,7 @@ static CURLcode imap_perform_list(struct connectdata *conn) /* Send the LIST command */ result = imap_sendf(conn, "LIST \"%s\" *", mailbox); - Curl_safefree(mailbox); + free(mailbox); } if(!result) @@ -718,7 +702,7 @@ static CURLcode imap_perform_select(struct connectdata *conn) /* Send the SELECT command */ result = imap_sendf(conn, "SELECT %s", mailbox); - Curl_safefree(mailbox); + free(mailbox); if(!result) state(conn, IMAP_SELECT); @@ -793,7 +777,7 @@ static CURLcode imap_perform_append(struct connectdata *conn) result = imap_sendf(conn, "APPEND %s (\\Seen) {%" CURL_FORMAT_CURL_OFF_T "}", mailbox, conn->data->state.infilesize); - Curl_safefree(mailbox); + free(mailbox); if(!result) state(conn, IMAP_APPEND); @@ -915,26 +899,16 @@ static CURLcode imap_state_capability_resp(struct connectdata *conn, /* Do we have a SASL based authentication mechanism? */ else if(wordlen > 5 && !memcmp(line, "AUTH=", 5)) { + size_t llen; + unsigned int mechbit; + line += 5; wordlen -= 5; /* Test the word for a matching authentication mechanism */ - if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_LOGIN)) - imapc->authmechs |= SASL_MECH_LOGIN; - else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_PLAIN)) - imapc->authmechs |= SASL_MECH_PLAIN; - else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_CRAM_MD5)) - imapc->authmechs |= SASL_MECH_CRAM_MD5; - else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_DIGEST_MD5)) - imapc->authmechs |= SASL_MECH_DIGEST_MD5; - else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_GSSAPI)) - imapc->authmechs |= SASL_MECH_GSSAPI; - else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_EXTERNAL)) - imapc->authmechs |= SASL_MECH_EXTERNAL; - else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_NTLM)) - imapc->authmechs |= SASL_MECH_NTLM; - else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_XOAUTH2)) - imapc->authmechs |= SASL_MECH_XOAUTH2; + if((mechbit = Curl_sasl_decode_mech(line, wordlen, &llen)) && + llen == wordlen) + imapc->sasl.authmechs |= mechbit; } line += wordlen; @@ -987,569 +961,36 @@ static CURLcode imap_state_starttls_resp(struct connectdata *conn, return result; } -/* For AUTHENTICATE PLAIN (without initial response) responses */ -static CURLcode imap_state_auth_plain_resp(struct connectdata *conn, - int imapcode, - imapstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - size_t len = 0; - char *plainauth = NULL; - - (void)instate; /* no use for this yet */ - - if(imapcode != '+') { - failf(data, "Access denied. %c", imapcode); - result = CURLE_LOGIN_DENIED; - } - else { - /* Create the authorisation message */ - result = Curl_sasl_create_plain_message(data, conn->user, conn->passwd, - &plainauth, &len); - if(!result && plainauth) { - /* Send the message */ - result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", plainauth); - - if(!result) - state(conn, IMAP_AUTHENTICATE_FINAL); - } - } - - Curl_safefree(plainauth); - - return result; -} - -/* For AUTHENTICATE LOGIN (without initial response) responses */ -static CURLcode imap_state_auth_login_resp(struct connectdata *conn, - int imapcode, - imapstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - size_t len = 0; - char *authuser = NULL; - - (void)instate; /* no use for this yet */ - - if(imapcode != '+') { - failf(data, "Access denied: %d", imapcode); - result = CURLE_LOGIN_DENIED; - } - else { - /* Create the user message */ - result = Curl_sasl_create_login_message(data, conn->user, - &authuser, &len); - if(!result && authuser) { - /* Send the user */ - result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", authuser); - - if(!result) - state(conn, IMAP_AUTHENTICATE_LOGIN_PASSWD); - } - } - - Curl_safefree(authuser); - - return result; -} - -/* For AUTHENTICATE LOGIN user entry responses */ -static CURLcode imap_state_auth_login_password_resp(struct connectdata *conn, - int imapcode, - imapstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - size_t len = 0; - char *authpasswd = NULL; - - (void)instate; /* no use for this yet */ - - if(imapcode != '+') { - failf(data, "Access denied: %d", imapcode); - result = CURLE_LOGIN_DENIED; - } - else { - /* Create the password message */ - result = Curl_sasl_create_login_message(data, conn->passwd, - &authpasswd, &len); - if(!result && authpasswd) { - /* Send the password */ - result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", authpasswd); - - if(!result) - state(conn, IMAP_AUTHENTICATE_FINAL); - } - } - - Curl_safefree(authpasswd); - - return result; -} - -#ifndef CURL_DISABLE_CRYPTO_AUTH -/* For AUTHENTICATE CRAM-MD5 responses */ -static CURLcode imap_state_auth_cram_resp(struct connectdata *conn, - int imapcode, - imapstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - char *chlg = NULL; - char *chlg64 = NULL; - char *rplyb64 = NULL; - size_t len = 0; - - (void)instate; /* no use for this yet */ - - if(imapcode != '+') { - failf(data, "Access denied: %d", imapcode); - return CURLE_LOGIN_DENIED; - } - - /* Get the challenge message */ - imap_get_message(data->state.buffer, &chlg64); - - /* Decode the challenge message */ - result = Curl_sasl_decode_cram_md5_message(chlg64, &chlg, &len); - if(result) { - /* Send the cancellation */ - result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", "*"); - - if(!result) - state(conn, IMAP_AUTHENTICATE_CANCEL); - } - else { - /* Create the response message */ - result = Curl_sasl_create_cram_md5_message(data, chlg, conn->user, - conn->passwd, &rplyb64, &len); - if(!result && rplyb64) { - /* Send the response */ - result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", rplyb64); - - if(!result) - state(conn, IMAP_AUTHENTICATE_FINAL); - } - } - - Curl_safefree(chlg); - Curl_safefree(rplyb64); - - return result; -} - -/* For AUTHENTICATE DIGEST-MD5 challenge responses */ -static CURLcode imap_state_auth_digest_resp(struct connectdata *conn, - int imapcode, - imapstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - char *chlg64 = NULL; - char *rplyb64 = NULL; - size_t len = 0; - - (void)instate; /* no use for this yet */ - - if(imapcode != '+') { - failf(data, "Access denied: %d", imapcode); - return CURLE_LOGIN_DENIED; - } - - /* Get the challenge message */ - imap_get_message(data->state.buffer, &chlg64); - - /* Create the response message */ - result = Curl_sasl_create_digest_md5_message(data, chlg64, - conn->user, conn->passwd, - "imap", &rplyb64, &len); - if(result) { - if(result == CURLE_BAD_CONTENT_ENCODING) { - /* Send the cancellation */ - result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", "*"); - - if(!result) - state(conn, IMAP_AUTHENTICATE_CANCEL); - } - } - else { - /* Send the response */ - result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", rplyb64); - - if(!result) - state(conn, IMAP_AUTHENTICATE_DIGESTMD5_RESP); - } - - Curl_safefree(rplyb64); - - return result; -} - -/* For AUTHENTICATE DIGEST-MD5 challenge-response responses */ -static CURLcode imap_state_auth_digest_resp_resp(struct connectdata *conn, - int imapcode, - imapstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - - (void)instate; /* no use for this yet */ - - if(imapcode != '+') { - failf(data, "Authentication failed: %d", imapcode); - result = CURLE_LOGIN_DENIED; - } - else { - /* Send an empty response */ - result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", ""); - - if(!result) - state(conn, IMAP_AUTHENTICATE_FINAL); - } - - return result; -} -#endif - -#ifdef USE_NTLM -/* For AUTHENTICATE NTLM (without initial response) responses */ -static CURLcode imap_state_auth_ntlm_resp(struct connectdata *conn, - int imapcode, - imapstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - size_t len = 0; - char *type1msg = NULL; - - (void)instate; /* no use for this yet */ - - if(imapcode != '+') { - failf(data, "Access denied: %d", imapcode); - result = CURLE_LOGIN_DENIED; - } - else { - /* Create the type-1 message */ - result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd, - &conn->ntlm, - &type1msg, &len); - if(!result && type1msg) { - /* Send the message */ - result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", type1msg); - - if(!result) - state(conn, IMAP_AUTHENTICATE_NTLM_TYPE2MSG); - } - } - - Curl_safefree(type1msg); - - return result; -} - -/* For NTLM type-2 responses (sent in reponse to our type-1 message) */ -static CURLcode imap_state_auth_ntlm_type2msg_resp(struct connectdata *conn, - int imapcode, - imapstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - char *type2msg = NULL; - char *type3msg = NULL; - size_t len = 0; - - (void)instate; /* no use for this yet */ - - if(imapcode != '+') { - failf(data, "Access denied: %d", imapcode); - result = CURLE_LOGIN_DENIED; - } - else { - /* Get the challenge message */ - imap_get_message(data->state.buffer, &type2msg); - - /* Decode the type-2 message */ - result = Curl_sasl_decode_ntlm_type2_message(data, type2msg, &conn->ntlm); - if(result) { - /* Send the cancellation */ - result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", "*"); - - if(!result) - state(conn, IMAP_AUTHENTICATE_CANCEL); - } - else { - /* Create the type-3 message */ - result = Curl_sasl_create_ntlm_type3_message(data, conn->user, - conn->passwd, &conn->ntlm, - &type3msg, &len); - if(!result && type3msg) { - /* Send the message */ - result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", type3msg); - - if(!result) - state(conn, IMAP_AUTHENTICATE_FINAL); - } - } - } - - Curl_safefree(type3msg); - - return result; -} -#endif - -#if defined(USE_WINDOWS_SSPI) -/* For AUTHENTICATE GSSAPI (without initial response) responses */ -static CURLcode imap_state_auth_gssapi_resp(struct connectdata *conn, - int imapcode, - imapstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - struct imap_conn *imapc = &conn->proto.imapc; - size_t len = 0; - char *respmsg = NULL; - - (void)instate; /* no use for this yet */ - - if(imapcode != '+') { - failf(data, "Access denied: %d", imapcode); - result = CURLE_LOGIN_DENIED; - } - else { - /* Create the initial response message */ - result = Curl_sasl_create_gssapi_user_message(data, conn->user, - conn->passwd, "imap", - imapc->mutual_auth, - NULL, &conn->krb5, - &respmsg, &len); - if(!result && respmsg) { - /* Send the message */ - result = Curl_pp_sendf(&imapc->pp, "%s", respmsg); - - if(!result) - state(conn, IMAP_AUTHENTICATE_GSSAPI_TOKEN); - } - } - - Curl_safefree(respmsg); - - return result; -} - -/* For AUTHENTICATE GSSAPI user token responses */ -static CURLcode imap_state_auth_gssapi_token_resp(struct connectdata *conn, - int imapcode, - imapstate instate) +/* For SASL authentication responses */ +static CURLcode imap_state_auth_resp(struct connectdata *conn, + int imapcode, + imapstate instate) { CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; struct imap_conn *imapc = &conn->proto.imapc; - char *chlgmsg = NULL; - char *respmsg = NULL; - size_t len = 0; + saslprogress progress; (void)instate; /* no use for this yet */ - if(imapcode != '+') { - failf(data, "Access denied: %d", imapcode); - result = CURLE_LOGIN_DENIED; - } - else { - /* Get the challenge message */ - imap_get_message(data->state.buffer, &chlgmsg); - - if(imapc->mutual_auth) - /* Decode the user token challenge and create the optional response - message */ - result = Curl_sasl_create_gssapi_user_message(data, NULL, NULL, NULL, - imapc->mutual_auth, - chlgmsg, &conn->krb5, - &respmsg, &len); - else - /* Decode the security challenge and create the response message */ - result = Curl_sasl_create_gssapi_security_message(data, chlgmsg, - &conn->krb5, - &respmsg, &len); - - if(result) { - if(result == CURLE_BAD_CONTENT_ENCODING) { - /* Send the cancellation */ - result = Curl_pp_sendf(&imapc->pp, "%s", "*"); - - if(!result) - state(conn, IMAP_AUTHENTICATE_CANCEL); - } - } - else { - /* Send the response */ - if(respmsg) - result = Curl_pp_sendf(&imapc->pp, "%s", respmsg); - else - result = Curl_pp_sendf(&imapc->pp, "%s", ""); - - if(!result) - state(conn, (imapc->mutual_auth ? IMAP_AUTHENTICATE_GSSAPI_NO_DATA : - IMAP_AUTHENTICATE_FINAL)); - } - } - - Curl_safefree(respmsg); - - return result; -} - -/* For AUTHENTICATE GSSAPI no data responses */ -static CURLcode imap_state_auth_gssapi_no_data_resp(struct connectdata *conn, - int imapcode, - imapstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - char *chlgmsg = NULL; - char *respmsg = NULL; - size_t len = 0; - - (void)instate; /* no use for this yet */ - - if(imapcode != '+') { - failf(data, "Access denied: %d", imapcode); - result = CURLE_LOGIN_DENIED; - } - else { - /* Get the challenge message */ - imap_get_message(data->state.buffer, &chlgmsg); - - /* Decode the security challenge and create the response message */ - result = Curl_sasl_create_gssapi_security_message(data, chlgmsg, - &conn->krb5, - &respmsg, &len); - if(result) { - if(result == CURLE_BAD_CONTENT_ENCODING) { - /* Send the cancellation */ - result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", "*"); - - if(!result) - state(conn, IMAP_AUTHENTICATE_CANCEL); - } - } - else { - /* Send the response */ - if(respmsg) { - result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", respmsg); - - if(!result) - state(conn, IMAP_AUTHENTICATE_FINAL); + result = Curl_sasl_continue(&imapc->sasl, conn, imapcode, &progress); + if(!result) + switch(progress) { + case SASL_DONE: + state(conn, IMAP_STOP); /* Authenticated */ + break; + case SASL_IDLE: /* No mechanism left after cancellation */ + if((!imapc->login_disabled) && (imapc->preftype & IMAP_TYPE_CLEARTEXT)) + /* Perform clear text authentication */ + result = imap_perform_login(conn); + else { + failf(data, "Authentication cancelled"); + result = CURLE_LOGIN_DENIED; } + break; + default: + break; } - } - - Curl_safefree(respmsg); - - return result; -} -#endif - -/* For AUTHENTICATE XOAUTH2 (without initial response) responses */ -static CURLcode imap_state_auth_xoauth2_resp(struct connectdata *conn, - int imapcode, - imapstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - size_t len = 0; - char *xoauth = NULL; - - (void)instate; /* no use for this yet */ - - if(imapcode != '+') { - failf(data, "Access denied: %d", imapcode); - result = CURLE_LOGIN_DENIED; - } - else { - /* Create the authorisation message */ - result = Curl_sasl_create_xoauth2_message(conn->data, conn->user, - conn->xoauth2_bearer, - &xoauth, &len); - if(!result && xoauth) { - /* Send the message */ - result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", xoauth); - - if(!result) - state(conn, IMAP_AUTHENTICATE_FINAL); - } - } - - Curl_safefree(xoauth); - - return result; -} - -/* For AUTHENTICATE cancellation responses */ -static CURLcode imap_state_auth_cancel_resp(struct connectdata *conn, - int imapcode, - imapstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - struct imap_conn *imapc = &conn->proto.imapc; - const char *mech = NULL; - char *initresp = NULL; - size_t len = 0; - imapstate state1 = IMAP_STOP; - imapstate state2 = IMAP_STOP; - - (void)imapcode; - (void)instate; /* no use for this yet */ - - /* Remove the offending mechanism from the supported list */ - imapc->authmechs ^= imapc->authused; - - /* Calculate alternative SASL login details */ - result = imap_calc_sasl_details(conn, &mech, &initresp, &len, &state1, - &state2); - - if(!result) { - /* Do we have any mechanisms left or can we fallback to clear text? */ - if(mech) { - /* Retry SASL based authentication */ - result = imap_perform_authenticate(conn, mech, initresp, state1, state2); - - Curl_safefree(initresp); - } - else if((!imapc->login_disabled) && - (imapc->preftype & IMAP_TYPE_CLEARTEXT)) - /* Perform clear text authentication */ - result = imap_perform_login(conn); - else { - failf(data, "Authentication cancelled"); - - result = CURLE_LOGIN_DENIED; - } - } - - return result; -} - -/* For final responses in the AUTHENTICATE sequence */ -static CURLcode imap_state_auth_final_resp(struct connectdata *conn, - int imapcode, - imapstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - - (void)instate; /* no use for this yet */ - - if(imapcode != 'O') { - failf(data, "Authentication failed: %d", imapcode); - result = CURLE_LOGIN_DENIED; - } - else - /* End of connect phase */ - state(conn, IMAP_STOP); return result; } @@ -1873,69 +1314,8 @@ static CURLcode imap_statemach_act(struct connectdata *conn) result = imap_state_starttls_resp(conn, imapcode, imapc->state); break; - case IMAP_AUTHENTICATE_PLAIN: - result = imap_state_auth_plain_resp(conn, imapcode, imapc->state); - break; - - case IMAP_AUTHENTICATE_LOGIN: - result = imap_state_auth_login_resp(conn, imapcode, imapc->state); - break; - - case IMAP_AUTHENTICATE_LOGIN_PASSWD: - result = imap_state_auth_login_password_resp(conn, imapcode, - imapc->state); - break; - -#ifndef CURL_DISABLE_CRYPTO_AUTH - case IMAP_AUTHENTICATE_CRAMMD5: - result = imap_state_auth_cram_resp(conn, imapcode, imapc->state); - break; - - case IMAP_AUTHENTICATE_DIGESTMD5: - result = imap_state_auth_digest_resp(conn, imapcode, imapc->state); - break; - - case IMAP_AUTHENTICATE_DIGESTMD5_RESP: - result = imap_state_auth_digest_resp_resp(conn, imapcode, imapc->state); - break; -#endif - -#ifdef USE_NTLM - case IMAP_AUTHENTICATE_NTLM: - result = imap_state_auth_ntlm_resp(conn, imapcode, imapc->state); - break; - - case IMAP_AUTHENTICATE_NTLM_TYPE2MSG: - result = imap_state_auth_ntlm_type2msg_resp(conn, imapcode, - imapc->state); - break; -#endif - -#if defined(USE_WINDOWS_SSPI) - case IMAP_AUTHENTICATE_GSSAPI: - result = imap_state_auth_gssapi_resp(conn, imapcode, imapc->state); - break; - - case IMAP_AUTHENTICATE_GSSAPI_TOKEN: - result = imap_state_auth_gssapi_token_resp(conn, imapcode, imapc->state); - break; - - case IMAP_AUTHENTICATE_GSSAPI_NO_DATA: - result = imap_state_auth_gssapi_no_data_resp(conn, imapcode, - imapc->state); - break; -#endif - - case IMAP_AUTHENTICATE_XOAUTH2: - result = imap_state_auth_xoauth2_resp(conn, imapcode, imapc->state); - break; - - case IMAP_AUTHENTICATE_CANCEL: - result = imap_state_auth_cancel_resp(conn, imapcode, imapc->state); - break; - - case IMAP_AUTHENTICATE_FINAL: - result = imap_state_auth_final_resp(conn, imapcode, imapc->state); + case IMAP_AUTHENTICATE: + result = imap_state_auth_resp(conn, imapcode, imapc->state); break; case IMAP_LOGIN: @@ -2062,7 +1442,7 @@ static CURLcode imap_connect(struct connectdata *conn, bool *done) /* Set the default preferred authentication type and mechanism */ imapc->preftype = IMAP_TYPE_ANY; - imapc->prefmech = SASL_AUTH_ANY; + Curl_sasl_init(&imapc->sasl, &saslimap); /* Initialise the pingpong layer */ Curl_pp_init(pp); @@ -2275,7 +1655,7 @@ static CURLcode imap_disconnect(struct connectdata *conn, bool dead_connection) Curl_pp_disconnect(&imapc->pp); /* Cleanup the SASL module */ - Curl_sasl_cleanup(conn, imapc->authused); + Curl_sasl_cleanup(conn, imapc->sasl.authused); /* Cleanup our connection based variables */ Curl_safefree(imapc->mailbox); @@ -2420,7 +1800,7 @@ static CURLcode imap_sendf(struct connectdata *conn, const char *fmt, ...) result = Curl_pp_vsendf(&imapc->pp, taggedfmt, ap); va_end(ap); - Curl_safefree(taggedfmt); + free(taggedfmt); return result; } @@ -2448,7 +1828,7 @@ static char *imap_atom(const char *str) if(!str) return NULL; - /* Count any unescapped characters */ + /* Count any unescaped characters */ p1 = str; while(*p1) { if(*p1 == '\\') @@ -2461,7 +1841,7 @@ static char *imap_atom(const char *str) p1++; } - /* Does the input contain any unescapped characters? */ + /* Does the input contain any unescaped characters? */ if(!backsp_count && !quote_count && !space_exists) return strdup(str); @@ -2549,69 +1929,42 @@ static CURLcode imap_parse_url_options(struct connectdata *conn) { CURLcode result = CURLE_OK; struct imap_conn *imapc = &conn->proto.imapc; - const char *options = conn->options; - const char *ptr = options; - bool reset = TRUE; + const char *ptr = conn->options; + + imapc->sasl.resetprefs = TRUE; - while(ptr && *ptr) { + while(!result && ptr && *ptr) { const char *key = ptr; + const char *value; while(*ptr && *ptr != '=') ptr++; - if(strnequal(key, "AUTH", 4)) { - size_t len = 0; - const char *value = ++ptr; + value = ptr + 1; - if(reset) { - reset = FALSE; - imapc->preftype = IMAP_TYPE_NONE; - imapc->prefmech = SASL_AUTH_NONE; - } - - while(*ptr && *ptr != ';') { - ptr++; - len++; - } - - if(strnequal(value, "*", len)) { - imapc->preftype = IMAP_TYPE_ANY; - imapc->prefmech = SASL_AUTH_ANY; - } - else if(strnequal(value, SASL_MECH_STRING_LOGIN, len)) { - imapc->preftype = IMAP_TYPE_SASL; - imapc->prefmech |= SASL_MECH_LOGIN; - } - else if(strnequal(value, SASL_MECH_STRING_PLAIN, len)) { - imapc->preftype = IMAP_TYPE_SASL; - imapc->prefmech |= SASL_MECH_PLAIN; - } - else if(strnequal(value, SASL_MECH_STRING_CRAM_MD5, len)) { - imapc->preftype = IMAP_TYPE_SASL; - imapc->prefmech |= SASL_MECH_CRAM_MD5; - } - else if(strnequal(value, SASL_MECH_STRING_DIGEST_MD5, len)) { - imapc->preftype = IMAP_TYPE_SASL; - imapc->prefmech |= SASL_MECH_DIGEST_MD5; - } - else if(strnequal(value, SASL_MECH_STRING_GSSAPI, len)) { - imapc->preftype = IMAP_TYPE_SASL; - imapc->prefmech |= SASL_MECH_GSSAPI; - } - else if(strnequal(value, SASL_MECH_STRING_NTLM, len)) { - imapc->preftype = IMAP_TYPE_SASL; - imapc->prefmech |= SASL_MECH_NTLM; - } - else if(strnequal(value, SASL_MECH_STRING_XOAUTH2, len)) { - imapc->preftype = IMAP_TYPE_SASL; - imapc->prefmech |= SASL_MECH_XOAUTH2; - } + while(*ptr && *ptr != ';') + ptr++; - if(*ptr == ';') - ptr++; - } + if(strnequal(key, "AUTH=", 5)) + result = Curl_sasl_parse_url_auth_option(&imapc->sasl, + value, ptr - value); else result = CURLE_URL_MALFORMAT; + + if(*ptr == ';') + ptr++; + } + + switch(imapc->sasl.prefmech) { + case SASL_AUTH_NONE: + imapc->preftype = IMAP_TYPE_NONE; + break; + case SASL_AUTH_DEFAULT: + imapc->preftype = IMAP_TYPE_ANY; + break; + default: + imapc->preftype = IMAP_TYPE_SASL; + break; } return result; @@ -2678,7 +2031,7 @@ static CURLcode imap_parse_url_path(struct connectdata *conn) /* Decode the value parameter */ result = Curl_urldecode(data, begin, ptr - begin, &value, &valuelen, TRUE); if(result) { - Curl_safefree(name); + free(name); return result; } @@ -2717,14 +2070,14 @@ static CURLcode imap_parse_url_path(struct connectdata *conn) value = NULL; } else { - Curl_safefree(name); - Curl_safefree(value); + free(name); + free(value); return CURLE_URL_MALFORMAT; } - Curl_safefree(name); - Curl_safefree(value); + free(name); + free(value); } /* Does the URL contain a query parameter? Only valid when we have a mailbox @@ -2786,108 +2139,4 @@ static CURLcode imap_parse_custom_request(struct connectdata *conn) return result; } -/*********************************************************************** - * - * imap_calc_sasl_details() - * - * Calculate the required login details for SASL authentication. - */ -static CURLcode imap_calc_sasl_details(struct connectdata *conn, - const char **mech, - char **initresp, size_t *len, - imapstate *state1, imapstate *state2) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - struct imap_conn *imapc = &conn->proto.imapc; - - /* Calculate the supported authentication mechanism, by decreasing order of - security, as well as the initial response where appropriate */ -#if defined(USE_WINDOWS_SSPI) - if((imapc->authmechs & SASL_MECH_GSSAPI) && - (imapc->prefmech & SASL_MECH_GSSAPI)) { - imapc->mutual_auth = FALSE; /* TODO: Calculate mutual authentication */ - - *mech = SASL_MECH_STRING_GSSAPI; - *state1 = IMAP_AUTHENTICATE_GSSAPI; - *state2 = IMAP_AUTHENTICATE_GSSAPI_TOKEN; - imapc->authused = SASL_MECH_GSSAPI; - - if(imapc->ir_supported || data->set.sasl_ir) - result = Curl_sasl_create_gssapi_user_message(data, conn->user, - conn->passwd, "imap", - imapc->mutual_auth, - NULL, &conn->krb5, - initresp, len); - } - else -#endif -#ifndef CURL_DISABLE_CRYPTO_AUTH - if((imapc->authmechs & SASL_MECH_DIGEST_MD5) && - (imapc->prefmech & SASL_MECH_DIGEST_MD5)) { - *mech = SASL_MECH_STRING_DIGEST_MD5; - *state1 = IMAP_AUTHENTICATE_DIGESTMD5; - imapc->authused = SASL_MECH_DIGEST_MD5; - } - else if((imapc->authmechs & SASL_MECH_CRAM_MD5) && - (imapc->prefmech & SASL_MECH_CRAM_MD5)) { - *mech = SASL_MECH_STRING_CRAM_MD5; - *state1 = IMAP_AUTHENTICATE_CRAMMD5; - imapc->authused = SASL_MECH_CRAM_MD5; - } - else -#endif -#ifdef USE_NTLM - if((imapc->authmechs & SASL_MECH_NTLM) && - (imapc->prefmech & SASL_MECH_NTLM)) { - *mech = SASL_MECH_STRING_NTLM; - *state1 = IMAP_AUTHENTICATE_NTLM; - *state2 = IMAP_AUTHENTICATE_NTLM_TYPE2MSG; - imapc->authused = SASL_MECH_NTLM; - - if(imapc->ir_supported || data->set.sasl_ir) - result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd, - &conn->ntlm, - initresp, len); - } - else -#endif - if(((imapc->authmechs & SASL_MECH_XOAUTH2) && - (imapc->prefmech & SASL_MECH_XOAUTH2) && - (imapc->prefmech != SASL_AUTH_ANY)) || conn->xoauth2_bearer) { - *mech = SASL_MECH_STRING_XOAUTH2; - *state1 = IMAP_AUTHENTICATE_XOAUTH2; - *state2 = IMAP_AUTHENTICATE_FINAL; - imapc->authused = SASL_MECH_XOAUTH2; - - if(imapc->ir_supported || data->set.sasl_ir) - result = Curl_sasl_create_xoauth2_message(data, conn->user, - conn->xoauth2_bearer, - initresp, len); - } - else if((imapc->authmechs & SASL_MECH_LOGIN) && - (imapc->prefmech & SASL_MECH_LOGIN)) { - *mech = SASL_MECH_STRING_LOGIN; - *state1 = IMAP_AUTHENTICATE_LOGIN; - *state2 = IMAP_AUTHENTICATE_LOGIN_PASSWD; - imapc->authused = SASL_MECH_LOGIN; - - if(imapc->ir_supported || data->set.sasl_ir) - result = Curl_sasl_create_login_message(data, conn->user, initresp, len); - } - else if((imapc->authmechs & SASL_MECH_PLAIN) && - (imapc->prefmech & SASL_MECH_PLAIN)) { - *mech = SASL_MECH_STRING_PLAIN; - *state1 = IMAP_AUTHENTICATE_PLAIN; - *state2 = IMAP_AUTHENTICATE_FINAL; - imapc->authused = SASL_MECH_PLAIN; - - if(imapc->ir_supported || data->set.sasl_ir) - result = Curl_sasl_create_plain_message(data, conn->user, conn->passwd, - initresp, len); - } - - return result; -} - #endif /* CURL_DISABLE_IMAP */ diff --git a/Utilities/cmcurl/lib/imap.h b/Utilities/cmcurl/lib/imap.h index 768fc4b..3189daa 100644 --- a/Utilities/cmcurl/lib/imap.h +++ b/Utilities/cmcurl/lib/imap.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2009 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2009 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -23,6 +23,7 @@ ***************************************************************************/ #include "pingpong.h" +#include "curl_sasl.h" /**************************************************************************** * IMAP unique setup @@ -35,20 +36,7 @@ typedef enum { IMAP_STARTTLS, IMAP_UPGRADETLS, /* asynchronously upgrade the connection to SSL/TLS (multi mode only) */ - IMAP_AUTHENTICATE_PLAIN, - IMAP_AUTHENTICATE_LOGIN, - IMAP_AUTHENTICATE_LOGIN_PASSWD, - IMAP_AUTHENTICATE_CRAMMD5, - IMAP_AUTHENTICATE_DIGESTMD5, - IMAP_AUTHENTICATE_DIGESTMD5_RESP, - IMAP_AUTHENTICATE_NTLM, - IMAP_AUTHENTICATE_NTLM_TYPE2MSG, - IMAP_AUTHENTICATE_GSSAPI, - IMAP_AUTHENTICATE_GSSAPI_TOKEN, - IMAP_AUTHENTICATE_GSSAPI_NO_DATA, - IMAP_AUTHENTICATE_XOAUTH2, - IMAP_AUTHENTICATE_CANCEL, - IMAP_AUTHENTICATE_FINAL, + IMAP_AUTHENTICATE, IMAP_LOGIN, IMAP_LIST, IMAP_SELECT, @@ -83,16 +71,13 @@ struct imap_conn { struct pingpong pp; imapstate state; /* Always use imap.c:state() to change state! */ bool ssldone; /* Is connect() over SSL done? */ - unsigned int authmechs; /* Accepted authentication mechanisms */ + struct SASL sasl; /* SASL-related parameters */ unsigned int preftype; /* Preferred authentication type */ - unsigned int prefmech; /* Preferred authentication mechanism */ - unsigned int authused; /* Auth mechanism used for the connection */ int cmdid; /* Last used command ID */ char resptag[5]; /* Response tag to wait for */ bool tls_supported; /* StartTLS capability supported by server */ bool login_disabled; /* LOGIN command disabled by server */ bool ir_supported; /* Initial response supported by server */ - bool mutual_auth; /* Mutual authentication enabled (GSSAPI only) */ char *mailbox; /* The last selected mailbox */ char *mailbox_uidvalidity; /* UIDVALIDITY parsed from select response */ }; diff --git a/Utilities/cmcurl/lib/inet_ntop.c b/Utilities/cmcurl/lib/inet_ntop.c index c327150..da9a3ab 100644 --- a/Utilities/cmcurl/lib/inet_ntop.c +++ b/Utilities/cmcurl/lib/inet_ntop.c @@ -32,8 +32,7 @@ #include <arpa/inet.h> #endif -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> +#include "curl_printf.h" #include "inet_ntop.h" diff --git a/Utilities/cmcurl/lib/inet_ntop.h b/Utilities/cmcurl/lib/inet_ntop.h index db28ed8..cc4bdbb 100644 --- a/Utilities/cmcurl/lib/inet_ntop.h +++ b/Utilities/cmcurl/lib/inet_ntop.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -31,7 +31,7 @@ char *Curl_inet_ntop(int af, const void *addr, char *buf, size_t size); #include <arpa/inet.h> #endif #define Curl_inet_ntop(af,addr,buf,size) \ - inet_ntop(af,addr,buf,(curl_socklen_t)size) + inet_ntop(af, addr, buf, (curl_socklen_t)size) #endif #endif /* HEADER_CURL_INET_NTOP_H */ diff --git a/Utilities/cmcurl/lib/krb5.c b/Utilities/cmcurl/lib/krb5.c index 7e82a68..ad7dd67 100644 --- a/Utilities/cmcurl/lib/krb5.c +++ b/Utilities/cmcurl/lib/krb5.c @@ -1,8 +1,8 @@ /* GSSAPI/krb5 support for FTP - loosely based on old krb4.c * - * Copyright (c) 1995, 1996, 1997, 1998, 1999, 2013 Kungliga Tekniska Högskolan + * Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). - * Copyright (c) 2004 - 2012 Daniel Stenberg + * Copyright (c) 2004 - 2015 Daniel Stenberg * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -34,13 +34,7 @@ #include "curl_setup.h" -#ifndef CURL_DISABLE_FTP -#ifdef HAVE_GSSAPI - -#ifdef HAVE_OLD_GSSMIT -#define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name -#define NCOMPAT 1 -#endif +#if defined(HAVE_GSSAPI) && !defined(CURL_DISABLE_FTP) #ifdef HAVE_NETDB_H #include <netdb.h> @@ -52,13 +46,11 @@ #include "curl_gssapi.h" #include "sendf.h" #include "curl_sec.h" -#include "curl_memory.h" #include "warnless.h" +#include "curl_printf.h" -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - -/* The last #include file should be: */ +/* The last #include files should be: */ +#include "curl_memory.h" #include "memdebug.h" #define LOCAL_ADDR (&conn->local_addr) @@ -121,8 +113,7 @@ krb5_overhead(void *app_data, int level, int len) } static int -krb5_encode(void *app_data, const void *from, int length, int level, void **to, - struct connectdata *conn UNUSED_PARAM) +krb5_encode(void *app_data, const void *from, int length, int level, void **to) { gss_ctx_id_t *context = app_data; gss_buffer_desc dec, enc; @@ -130,9 +121,6 @@ krb5_encode(void *app_data, const void *from, int length, int level, void **to, int state; int len; - /* shut gcc up */ - conn = NULL; - /* NOTE that the cast is safe, neither of the krb5, gnu gss and heimdal * libraries modify the input buffer in gss_seal() */ @@ -240,6 +228,7 @@ krb5_auth(void *app_data, struct connectdata *conn) &chan, gssresp, &output_buffer, + TRUE, NULL); if(gssresp) { @@ -257,7 +246,8 @@ krb5_auth(void *app_data, struct connectdata *conn) result = Curl_base64_encode(data, (char *)output_buffer.value, output_buffer.length, &p, &base64_sz); if(result) { - Curl_infof(data,"base64-encoding: %s\n", curl_easy_strerror(result)); + Curl_infof(data, "base64-encoding: %s\n", + curl_easy_strerror(result)); ret = AUTH_CONTINUE; break; } @@ -289,7 +279,8 @@ krb5_auth(void *app_data, struct connectdata *conn) (unsigned char **)&_gssresp.value, &_gssresp.length); if(result) { - Curl_failf(data,"base64-decoding: %s", curl_easy_strerror(result)); + Curl_failf(data, "base64-decoding: %s", + curl_easy_strerror(result)); ret = AUTH_CONTINUE; break; } @@ -338,5 +329,4 @@ struct Curl_sec_client_mech Curl_krb5_client_mech = { krb5_decode }; -#endif /* HAVE_GSSAPI */ -#endif /* CURL_DISABLE_FTP */ +#endif /* HAVE_GSSAPI && !CURL_DISABLE_FTP */ diff --git a/Utilities/cmcurl/lib/ldap.c b/Utilities/cmcurl/lib/ldap.c index ae48448..4d91282 100644 --- a/Utilities/cmcurl/lib/ldap.c +++ b/Utilities/cmcurl/lib/ldap.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -35,7 +35,7 @@ * OpenLDAP library versions, USE_OPENLDAP shall not be defined. */ -#ifdef CURL_LDAP_WIN /* Use Windows LDAP implementation. */ +#ifdef USE_WIN32_LDAP /* Use Windows LDAP implementation. */ # include <winldap.h> # ifndef LDAP_VENDOR_NAME # error Your Platform SDK is NOT sufficient for LDAP support! \ @@ -54,6 +54,15 @@ # endif /* HAVE_LDAP_SSL && HAVE_LDAP_SSL_H */ #endif +/* These are macros in both <wincrypt.h> (in above <winldap.h>) and typedefs + * in BoringSSL's <openssl/x509.h> + */ +#ifdef HAVE_BORINGSSL +# undef X509_NAME +# undef X509_CERT_PAIR +# undef X509_EXTENSIONS +#endif + #include "urldata.h" #include <curl/curl.h> #include "sendf.h" @@ -63,14 +72,14 @@ #include "strequal.h" #include "strtok.h" #include "curl_ldap.h" -#include "curl_memory.h" +#include "curl_multibyte.h" #include "curl_base64.h" #include "rawstr.h" #include "connect.h" +#include "curl_printf.h" -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - +/* The last #include files should be: */ +#include "curl_memory.h" #include "memdebug.h" #ifndef HAVE_LDAP_URL_PARSE @@ -80,10 +89,19 @@ typedef struct { char *lud_host; int lud_port; +#if defined(USE_WIN32_LDAP) + TCHAR *lud_dn; + TCHAR **lud_attrs; +#else char *lud_dn; char **lud_attrs; +#endif int lud_scope; +#if defined(USE_WIN32_LDAP) + TCHAR *lud_filter; +#else char *lud_filter; +#endif char **lud_exts; size_t lud_attrs_dups; /* how many were dup'ed, this field is not in the "real" struct so can only be used in code @@ -168,11 +186,11 @@ const struct Curl_handler Curl_handler_ldaps = { static CURLcode Curl_ldap(struct connectdata *conn, bool *done) { - CURLcode status = CURLE_OK; + CURLcode result = CURLE_OK; int rc = 0; LDAP *server = NULL; LDAPURLDesc *ludp = NULL; - LDAPMessage *result = NULL; + LDAPMessage *ldapmsg = NULL; LDAPMessage *entryIterator; int num = 0; struct SessionHandle *data=conn->data; @@ -182,7 +200,16 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) size_t val_b64_sz = 0; curl_off_t dlsize = 0; #ifdef LDAP_OPT_NETWORK_TIMEOUT - struct timeval ldap_timeout = {10,0}; /* 10 sec connection/search timeout */ + struct timeval ldap_timeout = {10, 0}; /* 10 sec connection/search timeout */ +#endif +#if defined(USE_WIN32_LDAP) + TCHAR *host = NULL; + TCHAR *user = NULL; + TCHAR *passwd = NULL; +#else + char *host = NULL; + char *user = NULL; + char *passwd = NULL; #endif *done = TRUE; /* unconditionally */ @@ -197,7 +224,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) #endif if(rc != 0) { failf(data, "LDAP local: %s", ldap_err2string(rc)); - status = CURLE_LDAP_INVALID_URL; + result = CURLE_LDAP_INVALID_URL; goto quit; } @@ -207,6 +234,32 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) infof(data, "LDAP local: trying to establish %s connection\n", ldap_ssl ? "encrypted" : "cleartext"); +#if defined(USE_WIN32_LDAP) + host = Curl_convert_UTF8_to_tchar(conn->host.name); + if(!host) { + result = CURLE_OUT_OF_MEMORY; + + goto quit; + } + + if(conn->bits.user_passwd) { + user = Curl_convert_UTF8_to_tchar(conn->user); + passwd = Curl_convert_UTF8_to_tchar(conn->passwd); + if(!user || !passwd) { + result = CURLE_OUT_OF_MEMORY; + + goto quit; + } + } +#else + host = conn->host.name; + + if(conn->bits.user_passwd) { + user = conn->user; + passwd = conn->passwd; + } +#endif + #ifdef LDAP_OPT_NETWORK_TIMEOUT ldap_set_option(NULL, LDAP_OPT_NETWORK_TIMEOUT, &ldap_timeout); #endif @@ -214,9 +267,9 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) if(ldap_ssl) { #ifdef HAVE_LDAP_SSL -#ifdef CURL_LDAP_WIN +#ifdef USE_WIN32_LDAP /* Win32 LDAP SDK doesn't support insecure mode without CA! */ - server = ldap_sslinit(conn->host.name, (int)conn->port, 1); + server = ldap_sslinit(host, (int)conn->port, 1); ldap_set_option(server, LDAP_OPT_SSL, LDAP_OPT_ON); #else int ldap_option; @@ -225,7 +278,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) rc = ldapssl_client_init(NULL, NULL); if(rc != LDAP_SUCCESS) { failf(data, "LDAP local: ldapssl_client_init %s", ldap_err2string(rc)); - status = CURLE_SSL_CERTPROBLEM; + result = CURLE_SSL_CERTPROBLEM; goto quit; } if(data->set.ssl.verifypeer) { @@ -237,7 +290,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) if(!ldap_ca) { failf(data, "LDAP local: ERROR %s CA cert not set!", (cert_type == LDAPSSL_CERT_FILETYPE_DER ? "DER" : "PEM")); - status = CURLE_SSL_CERTPROBLEM; + result = CURLE_SSL_CERTPROBLEM; goto quit; } infof(data, "LDAP local: using %s CA cert '%s'\n", @@ -248,7 +301,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) failf(data, "LDAP local: ERROR setting %s CA cert: %s", (cert_type == LDAPSSL_CERT_FILETYPE_DER ? "DER" : "PEM"), ldap_err2string(rc)); - status = CURLE_SSL_CERTPROBLEM; + result = CURLE_SSL_CERTPROBLEM; goto quit; } ldap_option = LDAPSSL_VERIFY_SERVER; @@ -259,14 +312,14 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) if(rc != LDAP_SUCCESS) { failf(data, "LDAP local: ERROR setting cert verify mode: %s", ldap_err2string(rc)); - status = CURLE_SSL_CERTPROBLEM; + result = CURLE_SSL_CERTPROBLEM; goto quit; } - server = ldapssl_init(conn->host.name, (int)conn->port, 1); + server = ldapssl_init(host, (int)conn->port, 1); if(server == NULL) { failf(data, "LDAP local: Cannot connect to %s:%ld", - conn->host.name, conn->port); - status = CURLE_COULDNT_CONNECT; + conn->host.dispname, conn->port); + result = CURLE_COULDNT_CONNECT; goto quit; } #elif defined(LDAP_OPT_X_TLS) @@ -275,12 +328,12 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) if((data->set.str[STRING_CERT_TYPE]) && (!Curl_raw_equal(data->set.str[STRING_CERT_TYPE], "PEM"))) { failf(data, "LDAP local: ERROR OpenLDAP only supports PEM cert-type!"); - status = CURLE_SSL_CERTPROBLEM; + result = CURLE_SSL_CERTPROBLEM; goto quit; } if(!ldap_ca) { failf(data, "LDAP local: ERROR PEM CA cert not set!"); - status = CURLE_SSL_CERTPROBLEM; + result = CURLE_SSL_CERTPROBLEM; goto quit; } infof(data, "LDAP local: using PEM CA cert: %s\n", ldap_ca); @@ -288,7 +341,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) if(rc != LDAP_SUCCESS) { failf(data, "LDAP local: ERROR setting PEM CA cert: %s", ldap_err2string(rc)); - status = CURLE_SSL_CERTPROBLEM; + result = CURLE_SSL_CERTPROBLEM; goto quit; } ldap_option = LDAP_OPT_X_TLS_DEMAND; @@ -300,14 +353,14 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) if(rc != LDAP_SUCCESS) { failf(data, "LDAP local: ERROR setting cert verify mode: %s", ldap_err2string(rc)); - status = CURLE_SSL_CERTPROBLEM; + result = CURLE_SSL_CERTPROBLEM; goto quit; } - server = ldap_init(conn->host.name, (int)conn->port); + server = ldap_init(host, (int)conn->port); if(server == NULL) { failf(data, "LDAP local: Cannot connect to %s:%ld", - conn->host.name, conn->port); - status = CURLE_COULDNT_CONNECT; + conn->host.dispname, conn->port); + result = CURLE_COULDNT_CONNECT; goto quit; } ldap_option = LDAP_OPT_X_TLS_HARD; @@ -315,7 +368,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) if(rc != LDAP_SUCCESS) { failf(data, "LDAP local: ERROR setting SSL/TLS mode: %s", ldap_err2string(rc)); - status = CURLE_SSL_CERTPROBLEM; + result = CURLE_SSL_CERTPROBLEM; goto quit; } /* @@ -323,7 +376,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) if(rc != LDAP_SUCCESS) { failf(data, "LDAP local: ERROR starting SSL/TLS mode: %s", ldap_err2string(rc)); - status = CURLE_SSL_CERTPROBLEM; + result = CURLE_SSL_CERTPROBLEM; goto quit; } */ @@ -332,126 +385,278 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) should check in first place if we can support LDAP SSL/TLS */ failf(data, "LDAP local: SSL/TLS not supported with this version " "of the OpenLDAP toolkit\n"); - status = CURLE_SSL_CERTPROBLEM; + result = CURLE_SSL_CERTPROBLEM; goto quit; #endif #endif #endif /* CURL_LDAP_USE_SSL */ } else { - server = ldap_init(conn->host.name, (int)conn->port); + server = ldap_init(host, (int)conn->port); if(server == NULL) { failf(data, "LDAP local: Cannot connect to %s:%ld", - conn->host.name, conn->port); - status = CURLE_COULDNT_CONNECT; + conn->host.dispname, conn->port); + result = CURLE_COULDNT_CONNECT; goto quit; } } -#ifdef CURL_LDAP_WIN +#ifdef USE_WIN32_LDAP ldap_set_option(server, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto); #endif - rc = ldap_simple_bind_s(server, - conn->bits.user_passwd ? conn->user : NULL, - conn->bits.user_passwd ? conn->passwd : NULL); + rc = ldap_simple_bind_s(server, user, passwd); if(!ldap_ssl && rc != 0) { ldap_proto = LDAP_VERSION2; ldap_set_option(server, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto); - rc = ldap_simple_bind_s(server, - conn->bits.user_passwd ? conn->user : NULL, - conn->bits.user_passwd ? conn->passwd : NULL); + rc = ldap_simple_bind_s(server, user, passwd); } if(rc != 0) { failf(data, "LDAP local: ldap_simple_bind_s %s", ldap_err2string(rc)); - status = CURLE_LDAP_CANNOT_BIND; + result = CURLE_LDAP_CANNOT_BIND; goto quit; } rc = ldap_search_s(server, ludp->lud_dn, ludp->lud_scope, - ludp->lud_filter, ludp->lud_attrs, 0, &result); + ludp->lud_filter, ludp->lud_attrs, 0, &ldapmsg); if(rc != 0 && rc != LDAP_SIZELIMIT_EXCEEDED) { failf(data, "LDAP remote: %s", ldap_err2string(rc)); - status = CURLE_LDAP_SEARCH_FAILED; + result = CURLE_LDAP_SEARCH_FAILED; goto quit; } - for(num = 0, entryIterator = ldap_first_entry(server, result); + for(num = 0, entryIterator = ldap_first_entry(server, ldapmsg); entryIterator; entryIterator = ldap_next_entry(server, entryIterator), num++) { BerElement *ber = NULL; +#if defined(USE_WIN32_LDAP) + TCHAR *attribute; +#else char *attribute; /*! suspicious that this isn't 'const' */ - char *dn = ldap_get_dn(server, entryIterator); +#endif int i; - Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"DN: ", 4); - Curl_client_write(conn, CLIENTWRITE_BODY, (char *)dn, 0); - Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1); + /* Get the DN and write it to the client */ + { + char *name; + size_t name_len; +#if defined(USE_WIN32_LDAP) + TCHAR *dn = ldap_get_dn(server, entryIterator); + name = Curl_convert_tchar_to_UTF8(dn); + if(!name) { + ldap_memfree(dn); + + result = CURLE_OUT_OF_MEMORY; + + goto quit; + } +#else + char *dn = name = ldap_get_dn(server, entryIterator); +#endif + name_len = strlen(name); + + result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"DN: ", 4); + if(result) { +#if defined(USE_WIN32_LDAP) + Curl_unicodefree(name); +#endif + ldap_memfree(dn); + + goto quit; + } + + result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *) name, + name_len); + if(result) { +#if defined(USE_WIN32_LDAP) + Curl_unicodefree(name); +#endif + ldap_memfree(dn); + + goto quit; + } + + result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1); + if(result) { +#if defined(USE_WIN32_LDAP) + Curl_unicodefree(name); +#endif + ldap_memfree(dn); + + goto quit; + } - dlsize += strlen(dn)+5; + dlsize += name_len + 5; +#if defined(USE_WIN32_LDAP) + Curl_unicodefree(name); +#endif + ldap_memfree(dn); + } + + /* Get the attributes and write them to the client */ for(attribute = ldap_first_attribute(server, entryIterator, &ber); attribute; attribute = ldap_next_attribute(server, entryIterator, ber)) { - BerValue **vals = ldap_get_values_len(server, entryIterator, attribute); + BerValue **vals; + size_t attr_len; +#if defined(USE_WIN32_LDAP) + char *attr = Curl_convert_tchar_to_UTF8(attribute); + if(!attr) { + if(ber) + ber_free(ber, 0); + + result = CURLE_OUT_OF_MEMORY; + + goto quit; + } +#else + char *attr = attribute; +#endif + attr_len = strlen(attr); + vals = ldap_get_values_len(server, entryIterator, attribute); if(vals != NULL) { for(i = 0; (vals[i] != NULL); i++) { - Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\t", 1); - Curl_client_write(conn, CLIENTWRITE_BODY, (char *) attribute, 0); - Curl_client_write(conn, CLIENTWRITE_BODY, (char *)": ", 2); - dlsize += strlen(attribute)+3; - - if((strlen(attribute) > 7) && - (strcmp(";binary", - (char *)attribute + - (strlen((char *)attribute) - 7)) == 0)) { + result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\t", 1); + if(result) { + ldap_value_free_len(vals); +#if defined(USE_WIN32_LDAP) + Curl_unicodefree(attr); +#endif + ldap_memfree(attribute); + if(ber) + ber_free(ber, 0); + + goto quit; + } + + result = Curl_client_write(conn, CLIENTWRITE_BODY, + (char *) attr, attr_len); + if(result) { + ldap_value_free_len(vals); +#if defined(USE_WIN32_LDAP) + Curl_unicodefree(attr); +#endif + ldap_memfree(attribute); + if(ber) + ber_free(ber, 0); + + goto quit; + } + + result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)": ", 2); + if(result) { + ldap_value_free_len(vals); +#if defined(USE_WIN32_LDAP) + Curl_unicodefree(attr); +#endif + ldap_memfree(attribute); + if(ber) + ber_free(ber, 0); + + goto quit; + } + + dlsize += attr_len + 3; + + if((attr_len > 7) && + (strcmp(";binary", (char *) attr + (attr_len - 7)) == 0)) { /* Binary attribute, encode to base64. */ - CURLcode error = Curl_base64_encode(data, - vals[i]->bv_val, - vals[i]->bv_len, - &val_b64, - &val_b64_sz); - if(error) { + result = Curl_base64_encode(data, + vals[i]->bv_val, + vals[i]->bv_len, + &val_b64, + &val_b64_sz); + if(result) { ldap_value_free_len(vals); +#if defined(USE_WIN32_LDAP) + Curl_unicodefree(attr); +#endif ldap_memfree(attribute); - ldap_memfree(dn); if(ber) ber_free(ber, 0); - status = error; + goto quit; } + if(val_b64_sz > 0) { - Curl_client_write(conn, CLIENTWRITE_BODY, val_b64, val_b64_sz); + result = Curl_client_write(conn, CLIENTWRITE_BODY, val_b64, + val_b64_sz); free(val_b64); + if(result) { + ldap_value_free_len(vals); +#if defined(USE_WIN32_LDAP) + Curl_unicodefree(attr); +#endif + ldap_memfree(attribute); + if(ber) + ber_free(ber, 0); + + goto quit; + } + dlsize += val_b64_sz; } } else { - Curl_client_write(conn, CLIENTWRITE_BODY, vals[i]->bv_val, - vals[i]->bv_len); + result = Curl_client_write(conn, CLIENTWRITE_BODY, vals[i]->bv_val, + vals[i]->bv_len); + if(result) { + ldap_value_free_len(vals); +#if defined(USE_WIN32_LDAP) + Curl_unicodefree(attr); +#endif + ldap_memfree(attribute); + if(ber) + ber_free(ber, 0); + + goto quit; + } + dlsize += vals[i]->bv_len; } - Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0); + + result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1); + if(result) { + ldap_value_free_len(vals); +#if defined(USE_WIN32_LDAP) + Curl_unicodefree(attr); +#endif + ldap_memfree(attribute); + if(ber) + ber_free(ber, 0); + + goto quit; + } + dlsize++; } /* Free memory used to store values */ ldap_value_free_len(vals); } - Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1); + + /* Free the attribute as we are done with it */ +#if defined(USE_WIN32_LDAP) + Curl_unicodefree(attr); +#endif + ldap_memfree(attribute); + + result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1); + if(result) + goto quit; dlsize++; Curl_pgrsSetDownloadCounter(data, dlsize); - ldap_memfree(attribute); } - ldap_memfree(dn); + if(ber) ber_free(ber, 0); } quit: - if(result) { - ldap_msgfree(result); + if(ldapmsg) { + ldap_msgfree(ldapmsg); LDAP_TRACE (("Received %d entries\n", num)); } if(rc == LDAP_SIZELIMIT_EXCEEDED) @@ -465,11 +670,17 @@ quit: ldapssl_client_deinit(); #endif /* HAVE_LDAP_SSL && CURL_HAS_NOVELL_LDAPSDK */ +#if defined(USE_WIN32_LDAP) + Curl_unicodefree(passwd); + Curl_unicodefree(user); + Curl_unicodefree(host); +#endif + /* no data to transfer */ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); connclose(conn, "LDAP connection always disable re-use"); - return status; + return result; } #ifdef DEBUG_LDAP @@ -513,57 +724,34 @@ static int str2scope (const char *p) /* * Split 'str' into strings separated by commas. - * Note: res[] points into 'str'. + * Note: out[] points into 'str'. */ -static char **split_str (char *str) +static bool split_str(char *str, char ***out, size_t *count) { - char **res, *lasts, *s; - int i; - - for(i = 2, s = strchr(str,','); s; i++) - s = strchr(++s,','); + char **res; + char *lasts; + char *s; + size_t i; + size_t items = 1; + + s = strchr(str, ','); + while(s) { + items++; + s = strchr(++s, ','); + } - res = calloc(i, sizeof(char*)); + res = calloc(items, sizeof(char *)); if(!res) - return NULL; + return FALSE; - for(i = 0, s = strtok_r(str, ",", &lasts); s; + for(i = 0, s = strtok_r(str, ",", &lasts); s && i < items; s = strtok_r(NULL, ",", &lasts), i++) res[i] = s; - return res; -} - -/* - * Unescape the LDAP-URL components - */ -static bool unescape_elements (void *data, LDAPURLDesc *ludp) -{ - int i; - - if(ludp->lud_filter) { - ludp->lud_filter = curl_easy_unescape(data, ludp->lud_filter, 0, NULL); - if(!ludp->lud_filter) - return FALSE; - } - - for(i = 0; ludp->lud_attrs && ludp->lud_attrs[i]; i++) { - ludp->lud_attrs[i] = curl_easy_unescape(data, ludp->lud_attrs[i], - 0, NULL); - if(!ludp->lud_attrs[i]) - return FALSE; - ludp->lud_attrs_dups++; - } - if(ludp->lud_dn) { - char *dn = ludp->lud_dn; - char *new_dn = curl_easy_unescape(data, dn, 0, NULL); + *out = res; + *count = items; - free(dn); - ludp->lud_dn = new_dn; - if(!new_dn) - return (FALSE); - } - return (TRUE); + return TRUE; } /* @@ -582,8 +770,11 @@ static bool unescape_elements (void *data, LDAPURLDesc *ludp) */ static int _ldap_url_parse2 (const struct connectdata *conn, LDAPURLDesc *ludp) { - char *p, *q; - int i; + int rc = LDAP_SUCCESS; + char *path; + char *p; + char *q; + size_t i; if(!conn->data || !conn->data->state.path || @@ -595,74 +786,190 @@ static int _ldap_url_parse2 (const struct connectdata *conn, LDAPURLDesc *ludp) ludp->lud_port = conn->remote_port; ludp->lud_host = conn->host.name; - /* parse DN (Distinguished Name). - */ - ludp->lud_dn = strdup(conn->data->state.path+1); - if(!ludp->lud_dn) + /* Duplicate the path */ + p = path = strdup(conn->data->state.path + 1); + if(!path) return LDAP_NO_MEMORY; - p = strchr(ludp->lud_dn, '?'); - LDAP_TRACE (("DN '%.*s'\n", p ? (size_t)(p-ludp->lud_dn) : - strlen(ludp->lud_dn), ludp->lud_dn)); + /* Parse the DN (Distinguished Name) */ + q = strchr(p, '?'); + if(q) + *q++ = '\0'; + + if(*p) { + char *dn = p; + char *unescaped; - if(!p) - goto success; + LDAP_TRACE (("DN '%s'\n", dn)); - *p++ = '\0'; + /* Unescape the DN */ + unescaped = curl_easy_unescape(conn->data, dn, 0, NULL); + if(!unescaped) { + rc = LDAP_NO_MEMORY; - /* parse attributes. skip "??". - */ + goto quit; + } + +#if defined(USE_WIN32_LDAP) + /* Convert the unescaped string to a tchar */ + ludp->lud_dn = Curl_convert_UTF8_to_tchar(unescaped); + + /* Free the unescaped string as we are done with it */ + Curl_unicodefree(unescaped); + + if(!ludp->lud_dn) { + rc = LDAP_NO_MEMORY; + + goto quit; + } +#else + ludp->lud_dn = unescaped; +#endif + } + + p = q; + if(!p) + goto quit; + + /* Parse the attributes. skip "??" */ q = strchr(p, '?'); if(q) *q++ = '\0'; - if(*p && *p != '?') { - ludp->lud_attrs = split_str(p); - if(!ludp->lud_attrs) - return LDAP_NO_MEMORY; + if(*p) { + char **attributes; + size_t count = 0; + + /* Split the string into an array of attributes */ + if(!split_str(p, &attributes, &count)) { + rc = LDAP_NO_MEMORY; + + goto quit; + } + + /* Allocate our array (+1 for the NULL entry) */ +#if defined(USE_WIN32_LDAP) + ludp->lud_attrs = calloc(count + 1, sizeof(TCHAR *)); +#else + ludp->lud_attrs = calloc(count + 1, sizeof(char *)); +#endif + if(!ludp->lud_attrs) { + free(attributes); + + rc = LDAP_NO_MEMORY; + + goto quit; + } + + for(i = 0; i < count; i++) { + char *unescaped; + + LDAP_TRACE (("attr[%d] '%s'\n", i, attributes[i])); + + /* Unescape the attribute */ + unescaped = curl_easy_unescape(conn->data, attributes[i], 0, NULL); + if(!unescaped) { + free(attributes); + + rc = LDAP_NO_MEMORY; + + goto quit; + } + +#if defined(USE_WIN32_LDAP) + /* Convert the unescaped string to a tchar */ + ludp->lud_attrs[i] = Curl_convert_UTF8_to_tchar(unescaped); + + /* Free the unescaped string as we are done with it */ + Curl_unicodefree(unescaped); + + if(!ludp->lud_attrs[i]) { + free(attributes); - for(i = 0; ludp->lud_attrs[i]; i++) - LDAP_TRACE (("attr[%d] '%s'\n", i, ludp->lud_attrs[i])); + rc = LDAP_NO_MEMORY; + + goto quit; + } +#else + ludp->lud_attrs[i] = unescaped; +#endif + + ludp->lud_attrs_dups++; + } + + free(attributes); } p = q; if(!p) - goto success; + goto quit; - /* parse scope. skip "??" - */ + /* Parse the scope. skip "??" */ q = strchr(p, '?'); if(q) *q++ = '\0'; - if(*p && *p != '?') { + if(*p) { ludp->lud_scope = str2scope(p); if(ludp->lud_scope == -1) { - return LDAP_INVALID_SYNTAX; + rc = LDAP_INVALID_SYNTAX; + + goto quit; } LDAP_TRACE (("scope %d\n", ludp->lud_scope)); } p = q; if(!p) - goto success; + goto quit; - /* parse filter - */ + /* Parse the filter */ q = strchr(p, '?'); if(q) *q++ = '\0'; - if(!*p) { - return LDAP_INVALID_SYNTAX; + + if(*p) { + char *filter = p; + char *unescaped; + + LDAP_TRACE (("filter '%s'\n", filter)); + + /* Unescape the filter */ + unescaped = curl_easy_unescape(conn->data, filter, 0, NULL); + if(!unescaped) { + rc = LDAP_NO_MEMORY; + + goto quit; + } + +#if defined(USE_WIN32_LDAP) + /* Convert the unescaped string to a tchar */ + ludp->lud_filter = Curl_convert_UTF8_to_tchar(unescaped); + + /* Free the unescaped string as we are done with it */ + Curl_unicodefree(unescaped); + + if(!ludp->lud_filter) { + rc = LDAP_NO_MEMORY; + + goto quit; + } +#else + ludp->lud_filter = unescaped; +#endif } - ludp->lud_filter = p; - LDAP_TRACE (("filter '%s'\n", ludp->lud_filter)); + p = q; + if(p && !*p) { + rc = LDAP_INVALID_SYNTAX; - success: - if(!unescape_elements(conn->data, ludp)) - return LDAP_NO_MEMORY; - return LDAP_SUCCESS; + goto quit; + } + +quit: + free(path); + + return rc; } static int _ldap_url_parse (const struct connectdata *conn, @@ -691,11 +998,8 @@ static void _ldap_free_urldesc (LDAPURLDesc *ludp) if(!ludp) return; - if(ludp->lud_dn) - free(ludp->lud_dn); - - if(ludp->lud_filter) - free(ludp->lud_filter); + free(ludp->lud_dn); + free(ludp->lud_filter); if(ludp->lud_attrs) { for(i = 0; i < ludp->lud_attrs_dups; i++) diff --git a/Utilities/cmcurl/lib/md4.c b/Utilities/cmcurl/lib/md4.c index 6930e02..60f73a2 100644 --- a/Utilities/cmcurl/lib/md4.c +++ b/Utilities/cmcurl/lib/md4.c @@ -1,282 +1,304 @@ -/*- - Copyright (C) 1990-2, RSA Data Security, Inc. All rights reserved. - - License to copy and use this software is granted provided that it - is identified as the "RSA Data Security, Inc. MD4 Message-Digest - Algorithm" in all material mentioning or referencing this software - or this function. - - License is also granted to make and use derivative works provided - that such works are identified as "derived from the RSA Data - Security, Inc. MD4 Message-Digest Algorithm" in all material - mentioning or referencing the derived work. - - RSA Data Security, Inc. makes no representations concerning either - the merchantability of this software or the suitability of this - software for any particular purpose. It is provided "as is" - without express or implied warranty of any kind. - - These notices must be retained in any copies of any part of this - documentation and/or software. +/* + * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc. + * MD4 Message-Digest Algorithm (RFC 1320). + * + * Homepage: + http://openwall.info/wiki/people/solar/software/public-domain-source-code/md4 + * + * Author: + * Alexander Peslyak, better known as Solar Designer <solar at openwall.com> + * + * This software was written by Alexander Peslyak in 2001. No copyright is + * claimed, and the software is hereby placed in the public domain. In case + * this attempt to disclaim copyright and place the software in the public + * domain is deemed null and void, then the software is Copyright (c) 2001 + * Alexander Peslyak and it is hereby released to the general public under the + * following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * There's ABSOLUTELY NO WARRANTY, express or implied. + * + * (This is a heavily cut-down "BSD license".) + * + * This differs from Colin Plumb's older public domain implementation in that + * no exactly 32-bit integer data type is required (any 32-bit or wider + * unsigned integer data type will do), there's no compile-time endianness + * configuration, and the function prototypes match OpenSSL's. No code from + * Colin Plumb's implementation has been reused; this comment merely compares + * the properties of the two independent implementations. + * + * The primary goals of this implementation are portability and ease of use. + * It is meant to be fast, but not as fast as possible. Some known + * optimizations are not included to reduce source code size and avoid + * compile-time configuration. */ #include "curl_setup.h" -/* NSS crypto library does not provide the MD4 hash algorithm, so that we have - * a local implementation of it */ -#ifdef USE_NSS +/* NSS and OS/400 crypto library do not provide the MD4 hash algorithm, so + * that we have a local implementation of it */ +#if defined(USE_NSS) || defined(USE_OS400CRYPTO) #include "curl_md4.h" #include "warnless.h" -typedef unsigned int UINT4; +#ifndef HAVE_OPENSSL -typedef struct MD4Context { - UINT4 state[4]; /* state (ABCD) */ - UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */ - unsigned char buffer[64]; /* input buffer */ +#include <string.h> + +/* Any 32-bit or wider unsigned integer data type will do */ +typedef unsigned int MD4_u32plus; + +typedef struct { + MD4_u32plus lo, hi; + MD4_u32plus a, b, c, d; + unsigned char buffer[64]; + MD4_u32plus block[16]; } MD4_CTX; -/* Constants for MD4Transform routine. - */ -#define S11 3 -#define S12 7 -#define S13 11 -#define S14 19 -#define S21 3 -#define S22 5 -#define S23 9 -#define S24 13 -#define S31 3 -#define S32 9 -#define S33 11 -#define S34 15 - -static void MD4Transform(UINT4 [4], const unsigned char [64]); -static void Encode(unsigned char *, UINT4 *, unsigned int); -static void Decode(UINT4 *, const unsigned char *, unsigned int); - -static unsigned char PADDING[64] = { - 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; - -/* F, G and H are basic MD4 functions. - */ -#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) -#define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z))) -#define H(x, y, z) ((x) ^ (y) ^ (z)) +static void MD4_Init(MD4_CTX *ctx); +static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size); +static void MD4_Final(unsigned char *result, MD4_CTX *ctx); -/* ROTATE_LEFT rotates x left n bits. +/* + * The basic MD4 functions. + * + * F and G are optimized compared to their RFC 1320 definitions, with the + * optimization for F borrowed from Colin Plumb's MD5 implementation. */ -#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) - -/* FF, GG and HH are transformations for rounds 1, 2 and 3 */ -/* Rotation is separate from addition to prevent recomputation */ -#define FF(a, b, c, d, x, s) { \ - (a) += F ((b), (c), (d)) + (x); \ - (a) = ROTATE_LEFT ((a), (s)); \ - } -#define GG(a, b, c, d, x, s) { \ - (a) += G ((b), (c), (d)) + (x) + (UINT4)0x5a827999; \ - (a) = ROTATE_LEFT ((a), (s)); \ - } -#define HH(a, b, c, d, x, s) { \ - (a) += H ((b), (c), (d)) + (x) + (UINT4)0x6ed9eba1; \ - (a) = ROTATE_LEFT ((a), (s)); \ - } +#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) +#define G(x, y, z) (((x) & ((y) | (z))) | ((y) & (z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) -/* MD4 initialization. Begins an MD4 operation, writing a new context. +/* + * The MD4 transformation for all three rounds. */ -static void MD4Init(MD4_CTX *context) +#define STEP(f, a, b, c, d, x, s) \ + (a) += f((b), (c), (d)) + (x); \ + (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); + +/* + * SET reads 4 input bytes in little-endian byte order and stores them + * in a properly aligned word in host byte order. + * + * The check for little-endian architectures that tolerate unaligned + * memory accesses is just an optimization. Nothing will break if it + * doesn't work. + */ +#if defined(__i386__) || defined(__x86_64__) || defined(__vax__) +#define SET(n) \ + (*(MD4_u32plus *)&ptr[(n) * 4]) +#define GET(n) \ + SET(n) +#else +#define SET(n) \ + (ctx->block[(n)] = \ + (MD4_u32plus)ptr[(n) * 4] | \ + ((MD4_u32plus)ptr[(n) * 4 + 1] << 8) | \ + ((MD4_u32plus)ptr[(n) * 4 + 2] << 16) | \ + ((MD4_u32plus)ptr[(n) * 4 + 3] << 24)) +#define GET(n) \ + (ctx->block[(n)]) +#endif + +/* + * This processes one or more 64-byte data blocks, but does NOT update + * the bit counters. There are no alignment requirements. + */ +static const void *body(MD4_CTX *ctx, const void *data, unsigned long size) { - context->count[0] = context->count[1] = 0; - - /* Load magic initialization constants. - */ - context->state[0] = 0x67452301; - context->state[1] = 0xefcdab89; - context->state[2] = 0x98badcfe; - context->state[3] = 0x10325476; + const unsigned char *ptr; + MD4_u32plus a, b, c, d; + MD4_u32plus saved_a, saved_b, saved_c, saved_d; + + ptr = (const unsigned char *)data; + + a = ctx->a; + b = ctx->b; + c = ctx->c; + d = ctx->d; + + do { + saved_a = a; + saved_b = b; + saved_c = c; + saved_d = d; + +/* Round 1 */ + STEP(F, a, b, c, d, SET(0), 3) + STEP(F, d, a, b, c, SET(1), 7) + STEP(F, c, d, a, b, SET(2), 11) + STEP(F, b, c, d, a, SET(3), 19) + STEP(F, a, b, c, d, SET(4), 3) + STEP(F, d, a, b, c, SET(5), 7) + STEP(F, c, d, a, b, SET(6), 11) + STEP(F, b, c, d, a, SET(7), 19) + STEP(F, a, b, c, d, SET(8), 3) + STEP(F, d, a, b, c, SET(9), 7) + STEP(F, c, d, a, b, SET(10), 11) + STEP(F, b, c, d, a, SET(11), 19) + STEP(F, a, b, c, d, SET(12), 3) + STEP(F, d, a, b, c, SET(13), 7) + STEP(F, c, d, a, b, SET(14), 11) + STEP(F, b, c, d, a, SET(15), 19) + +/* Round 2 */ + STEP(G, a, b, c, d, GET(0) + 0x5a827999, 3) + STEP(G, d, a, b, c, GET(4) + 0x5a827999, 5) + STEP(G, c, d, a, b, GET(8) + 0x5a827999, 9) + STEP(G, b, c, d, a, GET(12) + 0x5a827999, 13) + STEP(G, a, b, c, d, GET(1) + 0x5a827999, 3) + STEP(G, d, a, b, c, GET(5) + 0x5a827999, 5) + STEP(G, c, d, a, b, GET(9) + 0x5a827999, 9) + STEP(G, b, c, d, a, GET(13) + 0x5a827999, 13) + STEP(G, a, b, c, d, GET(2) + 0x5a827999, 3) + STEP(G, d, a, b, c, GET(6) + 0x5a827999, 5) + STEP(G, c, d, a, b, GET(10) + 0x5a827999, 9) + STEP(G, b, c, d, a, GET(14) + 0x5a827999, 13) + STEP(G, a, b, c, d, GET(3) + 0x5a827999, 3) + STEP(G, d, a, b, c, GET(7) + 0x5a827999, 5) + STEP(G, c, d, a, b, GET(11) + 0x5a827999, 9) + STEP(G, b, c, d, a, GET(15) + 0x5a827999, 13) + +/* Round 3 */ + STEP(H, a, b, c, d, GET(0) + 0x6ed9eba1, 3) + STEP(H, d, a, b, c, GET(8) + 0x6ed9eba1, 9) + STEP(H, c, d, a, b, GET(4) + 0x6ed9eba1, 11) + STEP(H, b, c, d, a, GET(12) + 0x6ed9eba1, 15) + STEP(H, a, b, c, d, GET(2) + 0x6ed9eba1, 3) + STEP(H, d, a, b, c, GET(10) + 0x6ed9eba1, 9) + STEP(H, c, d, a, b, GET(6) + 0x6ed9eba1, 11) + STEP(H, b, c, d, a, GET(14) + 0x6ed9eba1, 15) + STEP(H, a, b, c, d, GET(1) + 0x6ed9eba1, 3) + STEP(H, d, a, b, c, GET(9) + 0x6ed9eba1, 9) + STEP(H, c, d, a, b, GET(5) + 0x6ed9eba1, 11) + STEP(H, b, c, d, a, GET(13) + 0x6ed9eba1, 15) + STEP(H, a, b, c, d, GET(3) + 0x6ed9eba1, 3) + STEP(H, d, a, b, c, GET(11) + 0x6ed9eba1, 9) + STEP(H, c, d, a, b, GET(7) + 0x6ed9eba1, 11) + STEP(H, b, c, d, a, GET(15) + 0x6ed9eba1, 15) + + a += saved_a; + b += saved_b; + c += saved_c; + d += saved_d; + + ptr += 64; + } while(size -= 64); + + ctx->a = a; + ctx->b = b; + ctx->c = c; + ctx->d = d; + + return ptr; } -/* MD4 block update operation. Continues an MD4 message-digest - operation, processing another message block, and updating the - context. - */ -static void MD4Update(MD4_CTX *context, const unsigned char *input, - unsigned int inputLen) +static void MD4_Init(MD4_CTX *ctx) { - unsigned int i, bufindex, partLen; - - /* Compute number of bytes mod 64 */ - bufindex = (unsigned int)((context->count[0] >> 3) & 0x3F); - /* Update number of bits */ - if((context->count[0] += ((UINT4)inputLen << 3)) - < ((UINT4)inputLen << 3)) - context->count[1]++; - context->count[1] += ((UINT4)inputLen >> 29); - - partLen = 64 - bufindex; - /* Transform as many times as possible. - */ - if(inputLen >= partLen) { - memcpy(&context->buffer[bufindex], input, partLen); - MD4Transform (context->state, context->buffer); - - for(i = partLen; i + 63 < inputLen; i += 64) - MD4Transform (context->state, &input[i]); - - bufindex = 0; - } - else - i = 0; + ctx->a = 0x67452301; + ctx->b = 0xefcdab89; + ctx->c = 0x98badcfe; + ctx->d = 0x10325476; - /* Buffer remaining input */ - memcpy(&context->buffer[bufindex], &input[i], inputLen-i); + ctx->lo = 0; + ctx->hi = 0; } -/* MD4 padding. */ -static void MD4Pad(MD4_CTX *context) +static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size) { - unsigned char bits[8]; - unsigned int bufindex, padLen; + MD4_u32plus saved_lo; + unsigned long used, available; - /* Save number of bits */ - Encode (bits, context->count, 8); + saved_lo = ctx->lo; + if((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo) + ctx->hi++; + ctx->hi += (MD4_u32plus)size >> 29; - /* Pad out to 56 mod 64. - */ - bufindex = (unsigned int)((context->count[0] >> 3) & 0x3f); - padLen = (bufindex < 56) ? (56 - bufindex) : (120 - bufindex); - MD4Update (context, PADDING, padLen); + used = saved_lo & 0x3f; - /* Append length (before padding) */ - MD4Update (context, bits, 8); -} + if(used) { + available = 64 - used; -/* MD4 finalization. Ends an MD4 message-digest operation, writing the - the message digest and zeroizing the context. - */ -static void MD4Final (unsigned char digest[16], MD4_CTX *context) -{ - /* Do padding */ - MD4Pad (context); + if(size < available) { + memcpy(&ctx->buffer[used], data, size); + return; + } - /* Store state in digest */ - Encode (digest, context->state, 16); + memcpy(&ctx->buffer[used], data, available); + data = (const unsigned char *)data + available; + size -= available; + body(ctx, ctx->buffer, 64); + } - /* Zeroize sensitive information. - */ - memset(context, 0, sizeof(*context)); -} + if(size >= 64) { + data = body(ctx, data, size & ~(unsigned long)0x3f); + size &= 0x3f; + } -/* MD4 basic transformation. Transforms state based on block. - */ -static void MD4Transform (UINT4 state[4], const unsigned char block[64]) -{ - UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; - - Decode (x, block, 64); - - /* Round 1 */ - FF (a, b, c, d, x[ 0], S11); /* 1 */ - FF (d, a, b, c, x[ 1], S12); /* 2 */ - FF (c, d, a, b, x[ 2], S13); /* 3 */ - FF (b, c, d, a, x[ 3], S14); /* 4 */ - FF (a, b, c, d, x[ 4], S11); /* 5 */ - FF (d, a, b, c, x[ 5], S12); /* 6 */ - FF (c, d, a, b, x[ 6], S13); /* 7 */ - FF (b, c, d, a, x[ 7], S14); /* 8 */ - FF (a, b, c, d, x[ 8], S11); /* 9 */ - FF (d, a, b, c, x[ 9], S12); /* 10 */ - FF (c, d, a, b, x[10], S13); /* 11 */ - FF (b, c, d, a, x[11], S14); /* 12 */ - FF (a, b, c, d, x[12], S11); /* 13 */ - FF (d, a, b, c, x[13], S12); /* 14 */ - FF (c, d, a, b, x[14], S13); /* 15 */ - FF (b, c, d, a, x[15], S14); /* 16 */ - - /* Round 2 */ - GG (a, b, c, d, x[ 0], S21); /* 17 */ - GG (d, a, b, c, x[ 4], S22); /* 18 */ - GG (c, d, a, b, x[ 8], S23); /* 19 */ - GG (b, c, d, a, x[12], S24); /* 20 */ - GG (a, b, c, d, x[ 1], S21); /* 21 */ - GG (d, a, b, c, x[ 5], S22); /* 22 */ - GG (c, d, a, b, x[ 9], S23); /* 23 */ - GG (b, c, d, a, x[13], S24); /* 24 */ - GG (a, b, c, d, x[ 2], S21); /* 25 */ - GG (d, a, b, c, x[ 6], S22); /* 26 */ - GG (c, d, a, b, x[10], S23); /* 27 */ - GG (b, c, d, a, x[14], S24); /* 28 */ - GG (a, b, c, d, x[ 3], S21); /* 29 */ - GG (d, a, b, c, x[ 7], S22); /* 30 */ - GG (c, d, a, b, x[11], S23); /* 31 */ - GG (b, c, d, a, x[15], S24); /* 32 */ - - /* Round 3 */ - HH (a, b, c, d, x[ 0], S31); /* 33 */ - HH (d, a, b, c, x[ 8], S32); /* 34 */ - HH (c, d, a, b, x[ 4], S33); /* 35 */ - HH (b, c, d, a, x[12], S34); /* 36 */ - HH (a, b, c, d, x[ 2], S31); /* 37 */ - HH (d, a, b, c, x[10], S32); /* 38 */ - HH (c, d, a, b, x[ 6], S33); /* 39 */ - HH (b, c, d, a, x[14], S34); /* 40 */ - HH (a, b, c, d, x[ 1], S31); /* 41 */ - HH (d, a, b, c, x[ 9], S32); /* 42 */ - HH (c, d, a, b, x[ 5], S33); /* 43 */ - HH (b, c, d, a, x[13], S34); /* 44 */ - HH (a, b, c, d, x[ 3], S31); /* 45 */ - HH (d, a, b, c, x[11], S32); /* 46 */ - HH (c, d, a, b, x[ 7], S33); /* 47 */ - HH (b, c, d, a, x[15], S34); /* 48 */ - - state[0] += a; - state[1] += b; - state[2] += c; - state[3] += d; - - /* Zeroize sensitive information. - */ - memset(x, 0, sizeof(x)); + memcpy(ctx->buffer, data, size); } -/* Encodes input (UINT4) into output (unsigned char). Assumes len is - a multiple of 4. - */ -static void Encode(unsigned char *output, UINT4 *input, unsigned int len) +static void MD4_Final(unsigned char *result, MD4_CTX *ctx) { - unsigned int i, j; + unsigned long used, available; - for(i = 0, j = 0; j < len; i++, j += 4) { - output[j] = (unsigned char)(input[i] & 0xff); - output[j+1] = (unsigned char)((input[i] >> 8) & 0xff); - output[j+2] = (unsigned char)((input[i] >> 16) & 0xff); - output[j+3] = (unsigned char)((input[i] >> 24) & 0xff); - } -} + used = ctx->lo & 0x3f; -/* Decodes input (unsigned char) into output (UINT4). Assumes len is - a multiple of 4. - */ -static void Decode (UINT4 *output, const unsigned char *input, - unsigned int len) -{ - unsigned int i, j; + ctx->buffer[used++] = 0x80; + + available = 64 - used; - for(i = 0, j = 0; j < len; i++, j += 4) - output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | - (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24); + if(available < 8) { + memset(&ctx->buffer[used], 0, available); + body(ctx, ctx->buffer, 64); + used = 0; + available = 64; + } + + memset(&ctx->buffer[used], 0, available - 8); + + ctx->lo <<= 3; + ctx->buffer[56] = curlx_ultouc((ctx->lo)&0xff); + ctx->buffer[57] = curlx_ultouc((ctx->lo >> 8)&0xff); + ctx->buffer[58] = curlx_ultouc((ctx->lo >> 16)&0xff); + ctx->buffer[59] = curlx_ultouc((ctx->lo >> 24)&0xff); + ctx->buffer[60] = curlx_ultouc((ctx->hi)&0xff); + ctx->buffer[61] = curlx_ultouc((ctx->hi >> 8)&0xff); + ctx->buffer[62] = curlx_ultouc((ctx->hi >> 16)&0xff); + ctx->buffer[63] = curlx_ultouc(ctx->hi >> 24); + + body(ctx, ctx->buffer, 64); + + result[0] = curlx_ultouc((ctx->a)&0xff); + result[1] = curlx_ultouc((ctx->a >> 8)&0xff); + result[2] = curlx_ultouc((ctx->a >> 16)&0xff); + result[3] = curlx_ultouc(ctx->a >> 24); + result[4] = curlx_ultouc((ctx->b)&0xff); + result[5] = curlx_ultouc((ctx->b >> 8)&0xff); + result[6] = curlx_ultouc((ctx->b >> 16)&0xff); + result[7] = curlx_ultouc(ctx->b >> 24); + result[8] = curlx_ultouc((ctx->c)&0xff); + result[9] = curlx_ultouc((ctx->c >> 8)&0xff); + result[10] = curlx_ultouc((ctx->c >> 16)&0xff); + result[11] = curlx_ultouc(ctx->c >> 24); + result[12] = curlx_ultouc((ctx->d)&0xff); + result[13] = curlx_ultouc((ctx->d >> 8)&0xff); + result[14] = curlx_ultouc((ctx->d >> 16)&0xff); + result[15] = curlx_ultouc(ctx->d >> 24); + + memset(ctx, 0, sizeof(*ctx)); } +#endif + void Curl_md4it(unsigned char *output, const unsigned char *input, size_t len) { MD4_CTX ctx; - MD4Init(&ctx); - MD4Update(&ctx, input, curlx_uztoui(len)); - MD4Final(output, &ctx); + MD4_Init(&ctx); + MD4_Update(&ctx, input, curlx_uztoui(len)); + MD4_Final(output, &ctx); } -#endif /* USE_NSS */ +#endif /* defined(USE_NSS) || defined(USE_OS400CRYPTO) */ diff --git a/Utilities/cmcurl/lib/md5.c b/Utilities/cmcurl/lib/md5.c index af39fd4..b604c10 100644 --- a/Utilities/cmcurl/lib/md5.c +++ b/Utilities/cmcurl/lib/md5.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -28,11 +28,10 @@ #include "curl_hmac.h" #include "warnless.h" -#include "curl_memory.h" - #if defined(USE_GNUTLS_NETTLE) #include <nettle/md5.h> +#include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" @@ -58,6 +57,7 @@ static void MD5_Final(unsigned char digest[16], MD5_CTX * ctx) #elif defined(USE_GNUTLS) #include <gcrypt.h> +#include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" @@ -81,14 +81,12 @@ static void MD5_Final(unsigned char digest[16], MD5_CTX * ctx) gcry_md_close(*ctx); } -#elif defined(USE_SSLEAY) +#elif defined(USE_OPENSSL) /* When OpenSSL is available we use the MD5-function from OpenSSL */ - -# ifdef USE_OPENSSL -# include <openssl/md5.h> -# else -# include <md5.h> -# endif +#include <openssl/md5.h> +#include "curl_memory.h" +/* The last #include file should be: */ +#include "memdebug.h" #elif (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \ (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1040)) || \ @@ -103,6 +101,9 @@ static void MD5_Final(unsigned char digest[16], MD5_CTX * ctx) reliable than defining COMMON_DIGEST_FOR_OPENSSL on older cats. */ # include <CommonCrypto/CommonDigest.h> # define MD5_CTX CC_MD5_CTX +#include "curl_memory.h" +/* The last #include file should be: */ +#include "memdebug.h" static void MD5_Init(MD5_CTX *ctx) { @@ -124,6 +125,9 @@ static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx) #elif defined(_WIN32) #include <wincrypt.h> +#include "curl_memory.h" +/* The last #include file should be: */ +#include "memdebug.h" typedef struct { HCRYPTPROV hCryptProv; @@ -157,314 +161,326 @@ static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx) CryptReleaseContext(ctx->hCryptProv, 0); } +#elif defined(USE_AXTLS) +#include <axTLS/config.h> +#include <axTLS/os_int.h> +#include <axTLS/crypto.h> +#include "curl_memory.h" +/* The last #include file should be: */ +#include "memdebug.h" #else /* When no other crypto library is available we use this code segment */ - -/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All -rights reserved. - -License to copy and use this software is granted provided that it -is identified as the "RSA Data Security, Inc. MD5 Message-Digest -Algorithm" in all material mentioning or referencing this software -or this function. - -License is also granted to make and use derivative works provided -that such works are identified as "derived from the RSA Data -Security, Inc. MD5 Message-Digest Algorithm" in all material -mentioning or referencing the derived work. - -RSA Data Security, Inc. makes no representations concerning either -the merchantability of this software or the suitability of this -software for any particular purpose. It is provided "as is" -without express or implied warranty of any kind. - -These notices must be retained in any copies of any part of this -documentation and/or software. +/* + * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc. + * MD5 Message-Digest Algorithm (RFC 1321). + * + * Homepage: + http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5 + * + * Author: + * Alexander Peslyak, better known as Solar Designer <solar at openwall.com> + * + * This software was written by Alexander Peslyak in 2001. No copyright is + * claimed, and the software is hereby placed in the public domain. + * In case this attempt to disclaim copyright and place the software in the + * public domain is deemed null and void, then the software is + * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the + * general public under the following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * There's ABSOLUTELY NO WARRANTY, express or implied. + * + * (This is a heavily cut-down "BSD license".) + * + * This differs from Colin Plumb's older public domain implementation in that + * no exactly 32-bit integer data type is required (any 32-bit or wider + * unsigned integer data type will do), there's no compile-time endianness + * configuration, and the function prototypes match OpenSSL's. No code from + * Colin Plumb's implementation has been reused; this comment merely compares + * the properties of the two independent implementations. + * + * The primary goals of this implementation are portability and ease of use. + * It is meant to be fast, but not as fast as possible. Some known + * optimizations are not included to reduce source code size and avoid + * compile-time configuration. */ -/* UINT4 defines a four byte word */ -typedef unsigned int UINT4; +#include <string.h> -/* MD5 context. */ -struct md5_ctx { - UINT4 state[4]; /* state (ABCD) */ - UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */ - unsigned char buffer[64]; /* input buffer */ -}; - -typedef struct md5_ctx MD5_CTX; +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" -static void MD5_Init(struct md5_ctx *); -static void MD5_Update(struct md5_ctx *, const unsigned char *, unsigned int); -static void MD5_Final(unsigned char [16], struct md5_ctx *); +/* Any 32-bit or wider unsigned integer data type will do */ +typedef unsigned int MD5_u32plus; -/* Constants for MD5Transform routine. - */ +typedef struct { + MD5_u32plus lo, hi; + MD5_u32plus a, b, c, d; + unsigned char buffer[64]; + MD5_u32plus block[16]; +} MD5_CTX; -#define S11 7 -#define S12 12 -#define S13 17 -#define S14 22 -#define S21 5 -#define S22 9 -#define S23 14 -#define S24 20 -#define S31 4 -#define S32 11 -#define S33 16 -#define S34 23 -#define S41 6 -#define S42 10 -#define S43 15 -#define S44 21 - -static void MD5Transform(UINT4 [4], const unsigned char [64]); -static void Encode(unsigned char *, UINT4 *, unsigned int); -static void Decode(UINT4 *, const unsigned char *, unsigned int); - -static const unsigned char PADDING[64] = { - 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; +static void MD5_Init(MD5_CTX *ctx); +static void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size); +static void MD5_Final(unsigned char *result, MD5_CTX *ctx); -/* F, G, H and I are basic MD5 functions. +/* + * The basic MD5 functions. + * + * F and G are optimized compared to their RFC 1321 definitions for + * architectures that lack an AND-NOT instruction, just like in Colin Plumb's + * implementation. */ -#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) -#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) -#define H(x, y, z) ((x) ^ (y) ^ (z)) -#define I(x, y, z) ((y) ^ ((x) | (~z))) - -/* ROTATE_LEFT rotates x left n bits. +#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) +#define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y)))) +#define H(x, y, z) (((x) ^ (y)) ^ (z)) +#define H2(x, y, z) ((x) ^ ((y) ^ (z))) +#define I(x, y, z) ((y) ^ ((x) | ~(z))) + +/* + * The MD5 transformation for all four rounds. */ -#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) - -/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. -Rotation is separate from addition to prevent recomputation. +#define STEP(f, a, b, c, d, x, t, s) \ + (a) += f((b), (c), (d)) + (x) + (t); \ + (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \ + (a) += (b); + +/* + * SET reads 4 input bytes in little-endian byte order and stores them + * in a properly aligned word in host byte order. + * + * The check for little-endian architectures that tolerate unaligned + * memory accesses is just an optimization. Nothing will break if it + * doesn't work. */ -#define FF(a, b, c, d, x, s, ac) { \ - (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \ - (a) = ROTATE_LEFT ((a), (s)); \ - (a) += (b); \ - } -#define GG(a, b, c, d, x, s, ac) { \ - (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \ - (a) = ROTATE_LEFT ((a), (s)); \ - (a) += (b); \ - } -#define HH(a, b, c, d, x, s, ac) { \ - (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \ - (a) = ROTATE_LEFT ((a), (s)); \ - (a) += (b); \ - } -#define II(a, b, c, d, x, s, ac) { \ - (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \ - (a) = ROTATE_LEFT ((a), (s)); \ - (a) += (b); \ - } - -/* MD5 initialization. Begins an MD5 operation, writing a new context. +#if defined(__i386__) || defined(__x86_64__) || defined(__vax__) +#define SET(n) \ + (*(MD5_u32plus *)&ptr[(n) * 4]) +#define GET(n) \ + SET(n) +#else +#define SET(n) \ + (ctx->block[(n)] = \ + (MD5_u32plus)ptr[(n) * 4] | \ + ((MD5_u32plus)ptr[(n) * 4 + 1] << 8) | \ + ((MD5_u32plus)ptr[(n) * 4 + 2] << 16) | \ + ((MD5_u32plus)ptr[(n) * 4 + 3] << 24)) +#define GET(n) \ + (ctx->block[(n)]) +#endif + +/* + * This processes one or more 64-byte data blocks, but does NOT update + * the bit counters. There are no alignment requirements. */ -static void MD5_Init(struct md5_ctx *context) +static const void *body(MD5_CTX *ctx, const void *data, unsigned long size) { - context->count[0] = context->count[1] = 0; - /* Load magic initialization constants. */ - context->state[0] = 0x67452301; - context->state[1] = 0xefcdab89; - context->state[2] = 0x98badcfe; - context->state[3] = 0x10325476; + const unsigned char *ptr; + MD5_u32plus a, b, c, d; + MD5_u32plus saved_a, saved_b, saved_c, saved_d; + + ptr = (const unsigned char *)data; + + a = ctx->a; + b = ctx->b; + c = ctx->c; + d = ctx->d; + + do { + saved_a = a; + saved_b = b; + saved_c = c; + saved_d = d; + +/* Round 1 */ + STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7) + STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12) + STEP(F, c, d, a, b, SET(2), 0x242070db, 17) + STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22) + STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7) + STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12) + STEP(F, c, d, a, b, SET(6), 0xa8304613, 17) + STEP(F, b, c, d, a, SET(7), 0xfd469501, 22) + STEP(F, a, b, c, d, SET(8), 0x698098d8, 7) + STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12) + STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17) + STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22) + STEP(F, a, b, c, d, SET(12), 0x6b901122, 7) + STEP(F, d, a, b, c, SET(13), 0xfd987193, 12) + STEP(F, c, d, a, b, SET(14), 0xa679438e, 17) + STEP(F, b, c, d, a, SET(15), 0x49b40821, 22) + +/* Round 2 */ + STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5) + STEP(G, d, a, b, c, GET(6), 0xc040b340, 9) + STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14) + STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20) + STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5) + STEP(G, d, a, b, c, GET(10), 0x02441453, 9) + STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14) + STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20) + STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5) + STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9) + STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14) + STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20) + STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5) + STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9) + STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14) + STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20) + +/* Round 3 */ + STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4) + STEP(H2, d, a, b, c, GET(8), 0x8771f681, 11) + STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16) + STEP(H2, b, c, d, a, GET(14), 0xfde5380c, 23) + STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4) + STEP(H2, d, a, b, c, GET(4), 0x4bdecfa9, 11) + STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16) + STEP(H2, b, c, d, a, GET(10), 0xbebfbc70, 23) + STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4) + STEP(H2, d, a, b, c, GET(0), 0xeaa127fa, 11) + STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16) + STEP(H2, b, c, d, a, GET(6), 0x04881d05, 23) + STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4) + STEP(H2, d, a, b, c, GET(12), 0xe6db99e5, 11) + STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16) + STEP(H2, b, c, d, a, GET(2), 0xc4ac5665, 23) + +/* Round 4 */ + STEP(I, a, b, c, d, GET(0), 0xf4292244, 6) + STEP(I, d, a, b, c, GET(7), 0x432aff97, 10) + STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15) + STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21) + STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6) + STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10) + STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15) + STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21) + STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6) + STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10) + STEP(I, c, d, a, b, GET(6), 0xa3014314, 15) + STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21) + STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6) + STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10) + STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15) + STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21) + + a += saved_a; + b += saved_b; + c += saved_c; + d += saved_d; + + ptr += 64; + } while(size -= 64); + + ctx->a = a; + ctx->b = b; + ctx->c = c; + ctx->d = d; + + return ptr; } -/* MD5 block update operation. Continues an MD5 message-digest - operation, processing another message block, and updating the - context. - */ -static void MD5_Update (struct md5_ctx *context, /* context */ - const unsigned char *input, /* input block */ - unsigned int inputLen) /* length of input block */ +static void MD5_Init(MD5_CTX *ctx) { - unsigned int i, bufindex, partLen; + ctx->a = 0x67452301; + ctx->b = 0xefcdab89; + ctx->c = 0x98badcfe; + ctx->d = 0x10325476; - /* Compute number of bytes mod 64 */ - bufindex = (unsigned int)((context->count[0] >> 3) & 0x3F); + ctx->lo = 0; + ctx->hi = 0; +} - /* Update number of bits */ - if((context->count[0] += ((UINT4)inputLen << 3)) - < ((UINT4)inputLen << 3)) - context->count[1]++; - context->count[1] += ((UINT4)inputLen >> 29); +static void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size) +{ + MD5_u32plus saved_lo; + unsigned long used, available; + + saved_lo = ctx->lo; + if((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo) + ctx->hi++; + ctx->hi += (MD5_u32plus)size >> 29; - partLen = 64 - bufindex; + used = saved_lo & 0x3f; - /* Transform as many times as possible. */ - if(inputLen >= partLen) { - memcpy(&context->buffer[bufindex], input, partLen); - MD5Transform(context->state, context->buffer); + if(used) { + available = 64 - used; - for(i = partLen; i + 63 < inputLen; i += 64) - MD5Transform(context->state, &input[i]); + if(size < available) { + memcpy(&ctx->buffer[used], data, size); + return; + } + + memcpy(&ctx->buffer[used], data, available); + data = (const unsigned char *)data + available; + size -= available; + body(ctx, ctx->buffer, 64); + } - bufindex = 0; + if(size >= 64) { + data = body(ctx, data, size & ~(unsigned long)0x3f); + size &= 0x3f; } - else - i = 0; - /* Buffer remaining input */ - memcpy(&context->buffer[bufindex], &input[i], inputLen-i); + memcpy(ctx->buffer, data, size); } -/* MD5 finalization. Ends an MD5 message-digest operation, writing the - the message digest and zeroizing the context. -*/ -static void MD5_Final(unsigned char digest[16], /* message digest */ - struct md5_ctx *context) /* context */ +static void MD5_Final(unsigned char *result, MD5_CTX *ctx) { - unsigned char bits[8]; - unsigned int count, padLen; + unsigned long used, available; - /* Save number of bits */ - Encode (bits, context->count, 8); + used = ctx->lo & 0x3f; - /* Pad out to 56 mod 64. */ - count = (unsigned int)((context->count[0] >> 3) & 0x3f); - padLen = (count < 56) ? (56 - count) : (120 - count); - MD5_Update (context, PADDING, padLen); + ctx->buffer[used++] = 0x80; - /* Append length (before padding) */ - MD5_Update (context, bits, 8); + available = 64 - used; - /* Store state in digest */ - Encode (digest, context->state, 16); - - /* Zeroize sensitive information. */ - memset ((void *)context, 0, sizeof (*context)); -} - -/* MD5 basic transformation. Transforms state based on block. */ -static void MD5Transform(UINT4 state[4], - const unsigned char block[64]) -{ - UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; - - Decode (x, block, 64); - - /* Round 1 */ - FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ - FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ - FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ - FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ - FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ - FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ - FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ - FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ - FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ - FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ - FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ - FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ - FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ - FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ - FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ - FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ - - /* Round 2 */ - GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ - GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ - GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ - GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ - GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ - GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ - GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ - GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ - GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ - GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ - GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ - GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ - GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ - GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ - GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ - GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ - - /* Round 3 */ - HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ - HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ - HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ - HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ - HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ - HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ - HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ - HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ - HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ - HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ - HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ - HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ - HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ - HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ - HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ - HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ - - /* Round 4 */ - II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ - II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ - II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ - II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ - II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ - II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ - II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ - II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ - II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ - II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ - II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ - II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ - II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ - II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ - II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ - II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ - - state[0] += a; - state[1] += b; - state[2] += c; - state[3] += d; - - /* Zeroize sensitive information. */ - memset((void *)x, 0, sizeof (x)); -} - -/* Encodes input (UINT4) into output (unsigned char). Assumes len is - a multiple of 4. - */ -static void Encode (unsigned char *output, - UINT4 *input, - unsigned int len) -{ - unsigned int i, j; - - for(i = 0, j = 0; j < len; i++, j += 4) { - output[j] = (unsigned char)(input[i] & 0xff); - output[j+1] = (unsigned char)((input[i] >> 8) & 0xff); - output[j+2] = (unsigned char)((input[i] >> 16) & 0xff); - output[j+3] = (unsigned char)((input[i] >> 24) & 0xff); + if(available < 8) { + memset(&ctx->buffer[used], 0, available); + body(ctx, ctx->buffer, 64); + used = 0; + available = 64; } -} - -/* Decodes input (unsigned char) into output (UINT4). Assumes len is - a multiple of 4. -*/ -static void Decode (UINT4 *output, - const unsigned char *input, - unsigned int len) -{ - unsigned int i, j; - for(i = 0, j = 0; j < len; i++, j += 4) - output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | - (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24); + memset(&ctx->buffer[used], 0, available - 8); + + ctx->lo <<= 3; + ctx->buffer[56] = curlx_ultouc((ctx->lo)&0xff); + ctx->buffer[57] = curlx_ultouc((ctx->lo >> 8)&0xff); + ctx->buffer[58] = curlx_ultouc((ctx->lo >> 16)&0xff); + ctx->buffer[59] = curlx_ultouc(ctx->lo >> 24); + ctx->buffer[60] = curlx_ultouc((ctx->hi)&0xff); + ctx->buffer[61] = curlx_ultouc((ctx->hi >> 8)&0xff); + ctx->buffer[62] = curlx_ultouc((ctx->hi >> 16)&0xff); + ctx->buffer[63] = curlx_ultouc(ctx->hi >> 24); + + body(ctx, ctx->buffer, 64); + + result[0] = curlx_ultouc((ctx->a)&0xff); + result[1] = curlx_ultouc((ctx->a >> 8)&0xff); + result[2] = curlx_ultouc((ctx->a >> 16)&0xff); + result[3] = curlx_ultouc(ctx->a >> 24); + result[4] = curlx_ultouc((ctx->b)&0xff); + result[5] = curlx_ultouc((ctx->b >> 8)&0xff); + result[6] = curlx_ultouc((ctx->b >> 16)&0xff); + result[7] = curlx_ultouc(ctx->b >> 24); + result[8] = curlx_ultouc((ctx->c)&0xff); + result[9] = curlx_ultouc((ctx->c >> 8)&0xff); + result[10] = curlx_ultouc((ctx->c >> 16)&0xff); + result[11] = curlx_ultouc(ctx->c >> 24); + result[12] = curlx_ultouc((ctx->d)&0xff); + result[13] = curlx_ultouc((ctx->d >> 8)&0xff); + result[14] = curlx_ultouc((ctx->d >> 16)&0xff); + result[15] = curlx_ultouc(ctx->d >> 24); + + memset(ctx, 0, sizeof(*ctx)); } #endif /* CRYPTO LIBS */ -/* The last #include file should be: */ -#include "memdebug.h" - const HMAC_params Curl_HMAC_MD5[] = { { (HMAC_hinit_func) MD5_Init, /* Hash initialization function. */ @@ -486,6 +502,9 @@ const MD5_params Curl_DIGEST_MD5[] = { } }; +/* + * @unittest: 1601 + */ void Curl_md5it(unsigned char *outbuffer, /* 16 bytes */ const unsigned char *input) { diff --git a/Utilities/cmcurl/lib/memdebug.c b/Utilities/cmcurl/lib/memdebug.c index 4afa620..dd8889b 100644 --- a/Utilities/cmcurl/lib/memdebug.c +++ b/Utilities/cmcurl/lib/memdebug.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -26,8 +26,7 @@ #include <curl/curl.h> -#define _MPRINTF_REPLACE -#include <curl/mprintf.h> +#include "curl_printf.h" #include "urldata.h" #define MEMDEBUG_NODEFINES /* don't redefine the standard functions */ @@ -113,7 +112,7 @@ void curl_memdebug(const char *logname) { if(!logfile) { if(logname && *logname) - logfile = fopen(logname, "w"); + logfile = fopen(logname, FOPEN_WRITETEXT); else logfile = stderr; #ifdef MEMDEBUG_LOG_SYNC @@ -343,10 +342,10 @@ curl_socket_t curl_socket(int domain, int type, int protocol, int line, const char *source) { const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ? - "FD %s:%d socket() = %d\n" : - (sizeof(curl_socket_t) == sizeof(long)) ? - "FD %s:%d socket() = %ld\n" : - "FD %s:%d socket() = %zd\n" ; + "FD %s:%d socket() = %d\n" : + (sizeof(curl_socket_t) == sizeof(long)) ? + "FD %s:%d socket() = %ld\n" : + "FD %s:%d socket() = %zd\n"; curl_socket_t sockfd = socket(domain, type, protocol); @@ -362,10 +361,10 @@ int curl_socketpair(int domain, int type, int protocol, int line, const char *source) { const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ? - "FD %s:%d socketpair() = %d %d\n" : - (sizeof(curl_socket_t) == sizeof(long)) ? - "FD %s:%d socketpair() = %ld %ld\n" : - "FD %s:%d socketpair() = %zd %zd\n" ; + "FD %s:%d socketpair() = %d %d\n" : + (sizeof(curl_socket_t) == sizeof(long)) ? + "FD %s:%d socketpair() = %ld %ld\n" : + "FD %s:%d socketpair() = %zd %zd\n"; int res = socketpair(domain, type, protocol, socket_vector); @@ -380,10 +379,10 @@ curl_socket_t curl_accept(curl_socket_t s, void *saddr, void *saddrlen, int line, const char *source) { const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ? - "FD %s:%d accept() = %d\n" : - (sizeof(curl_socket_t) == sizeof(long)) ? - "FD %s:%d accept() = %ld\n" : - "FD %s:%d accept() = %zd\n" ; + "FD %s:%d accept() = %d\n" : + (sizeof(curl_socket_t) == sizeof(long)) ? + "FD %s:%d accept() = %ld\n" : + "FD %s:%d accept() = %zd\n"; struct sockaddr *addr = (struct sockaddr *)saddr; curl_socklen_t *addrlen = (curl_socklen_t *)saddrlen; @@ -400,10 +399,10 @@ curl_socket_t curl_accept(curl_socket_t s, void *saddr, void *saddrlen, void curl_mark_sclose(curl_socket_t sockfd, int line, const char *source) { const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ? - "FD %s:%d sclose(%d)\n" : - (sizeof(curl_socket_t) == sizeof(long)) ? - "FD %s:%d sclose(%ld)\n" : - "FD %s:%d sclose(%zd)\n" ; + "FD %s:%d sclose(%d)\n": + (sizeof(curl_socket_t) == sizeof(long)) ? + "FD %s:%d sclose(%ld)\n": + "FD %s:%d sclose(%zd)\n"; if(source) curl_memlog(fmt, source, line, sockfd); diff --git a/Utilities/cmcurl/lib/memdebug.h b/Utilities/cmcurl/lib/memdebug.h index bd565c8..cfac1e0 100644 --- a/Utilities/cmcurl/lib/memdebug.h +++ b/Utilities/cmcurl/lib/memdebug.h @@ -8,7 +8,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -104,13 +104,13 @@ CURL_EXTERN int curl_fclose(FILE *file, int line, const char *source); #endif #define socket(domain,type,protocol)\ - curl_socket(domain,type,protocol,__LINE__,__FILE__) + curl_socket(domain, type, protocol, __LINE__, __FILE__) #undef accept /* for those with accept as a macro */ #define accept(sock,addr,len)\ - curl_accept(sock,addr,len,__LINE__,__FILE__) + curl_accept(sock, addr, len, __LINE__, __FILE__) #ifdef HAVE_SOCKETPAIR #define socketpair(domain,type,protocol,socket_vector)\ - curl_socketpair(domain,type,protocol,socket_vector,__LINE__,__FILE__) + curl_socketpair(domain, type, protocol, socket_vector, __LINE__, __FILE__) #endif #ifdef HAVE_GETADDRINFO @@ -119,25 +119,25 @@ CURL_EXTERN int curl_fclose(FILE *file, int line, const char *source); our macro as for other platforms. Instead, we redefine the new name they define getaddrinfo to become! */ #define ogetaddrinfo(host,serv,hint,res) \ - curl_dogetaddrinfo(host,serv,hint,res,__LINE__,__FILE__) + curl_dogetaddrinfo(host, serv, hint, res, __LINE__, __FILE__) #else #undef getaddrinfo #define getaddrinfo(host,serv,hint,res) \ - curl_dogetaddrinfo(host,serv,hint,res,__LINE__,__FILE__) + curl_dogetaddrinfo(host, serv, hint, res, __LINE__, __FILE__) #endif #endif /* HAVE_GETADDRINFO */ #ifdef HAVE_GETNAMEINFO #undef getnameinfo #define getnameinfo(sa,salen,host,hostlen,serv,servlen,flags) \ - curl_dogetnameinfo(sa,salen,host,hostlen,serv,servlen,flags, __LINE__, \ - __FILE__) + curl_dogetnameinfo(sa, salen, host, hostlen, serv, servlen, flags, \ + __LINE__, __FILE__) #endif /* HAVE_GETNAMEINFO */ #ifdef HAVE_FREEADDRINFO #undef freeaddrinfo #define freeaddrinfo(data) \ - curl_dofreeaddrinfo(data,__LINE__,__FILE__) + curl_dofreeaddrinfo(data, __LINE__, __FILE__) #endif /* HAVE_FREEADDRINFO */ /* sclose is probably already defined, redefine it! */ @@ -171,6 +171,6 @@ CURL_EXTERN int curl_fclose(FILE *file, int line, const char *source); */ #define Curl_safefree(ptr) \ - do {if((ptr)) {free((ptr)); (ptr) = NULL;}} WHILE_FALSE + do { free((ptr)); (ptr) = NULL;} WHILE_FALSE #endif /* HEADER_CURL_MEMDEBUG_H */ diff --git a/Utilities/cmcurl/lib/multi.c b/Utilities/cmcurl/lib/multi.c index a1dc2c8..0052087 100644 --- a/Utilities/cmcurl/lib/multi.c +++ b/Utilities/cmcurl/lib/multi.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -39,14 +39,10 @@ #include "warnless.h" #include "speedcheck.h" #include "conncache.h" -#include "bundles.h" #include "multihandle.h" #include "pipeline.h" #include "sigpipe.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - +#include "curl_printf.h" #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" @@ -66,15 +62,11 @@ #define GOOD_MULTI_HANDLE(x) \ ((x) && (((struct Curl_multi *)(x))->type == CURL_MULTI_HANDLE)) -#define GOOD_EASY_HANDLE(x) \ - ((x) && (((struct SessionHandle *)(x))->magic == CURLEASY_MAGIC_NUMBER)) static void singlesocket(struct Curl_multi *multi, struct SessionHandle *data); static int update_timer(struct Curl_multi *multi); -static bool isHandleAtHead(struct SessionHandle *handle, - struct curl_llist *pipeline); static CURLMcode add_next_timeout(struct timeval now, struct Curl_multi *multi, struct SessionHandle *d); @@ -89,6 +81,7 @@ static const char * const statename[]={ "WAITRESOLVE", "WAITCONNECT", "WAITPROXYCONNECT", + "SENDPROTOCONNECT", "PROTOCONNECT", "WAITDO", "DO", @@ -113,20 +106,23 @@ static void mstate(struct SessionHandle *data, CURLMstate state #endif ) { -#ifdef DEBUGBUILD - long connection_id = -5000; -#endif CURLMstate oldstate = data->mstate; +#if defined(DEBUGBUILD) && defined(CURL_DISABLE_VERBOSE_STRINGS) + (void) lineno; +#endif + if(oldstate == state) /* don't bother when the new state is the same as the old state */ return; data->mstate = state; -#ifdef DEBUGBUILD +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) if(data->mstate >= CURLM_STATE_CONNECT_PEND && data->mstate < CURLM_STATE_COMPLETED) { + long connection_id = -5000; + if(data->easy_conn) connection_id = data->easy_conn->connection_id; @@ -136,6 +132,7 @@ static void mstate(struct SessionHandle *data, CURLMstate state (void *)data, lineno, connection_id); } #endif + if(state == CURLM_STATE_COMPLETED) /* changing to COMPLETED means there's one less easy handle 'alive' */ data->multi->num_alive--; @@ -153,7 +150,6 @@ static void mstate(struct SessionHandle *data, CURLMstate state struct Curl_sh_entry { struct SessionHandle *easy; - time_t timestamp; int action; /* what action READ/WRITE this socket waits for */ curl_socket_t socket; /* mainly to ease debugging */ void *socketp; /* settable by users with curl_multi_assign() */ @@ -180,11 +176,12 @@ static struct Curl_sh_entry *sh_addentry(struct curl_hash *sh, check = calloc(1, sizeof(struct Curl_sh_entry)); if(!check) return NULL; /* major failure */ + check->easy = data; check->socket = s; /* make/add new hash entry */ - if(NULL == Curl_hash_add(sh, (char *)&s, sizeof(curl_socket_t), check)) { + if(!Curl_hash_add(sh, (char *)&s, sizeof(curl_socket_t), check)) { free(check); return NULL; /* major failure */ } @@ -214,8 +211,7 @@ static void sh_freeentry(void *freethis) { struct Curl_sh_entry *p = (struct Curl_sh_entry *) freethis; - if(p) - free(p); + free(p); } static size_t fd_key_compare(void *k1, size_t k1_len, void *k2, size_t k2_len) @@ -251,10 +247,10 @@ static size_t hash_fd(void *key, size_t key_length, size_t slots_num) * per call." * */ -static struct curl_hash *sh_init(int hashsize) +static int sh_init(struct curl_hash *hash, int hashsize) { - return Curl_hash_alloc(hashsize, hash_fd, fd_key_compare, - sh_freeentry); + return Curl_hash_init(hash, hashsize, hash_fd, fd_key_compare, + sh_freeentry); } /* @@ -293,16 +289,13 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */ multi->type = CURL_MULTI_HANDLE; - multi->hostcache = Curl_mk_dnscache(); - if(!multi->hostcache) + if(Curl_mk_dnscache(&multi->hostcache)) goto error; - multi->sockhash = sh_init(hashsize); - if(!multi->sockhash) + if(sh_init(&multi->sockhash, hashsize)) goto error; - multi->conn_cache = Curl_conncache_init(chashsize); - if(!multi->conn_cache) + if(Curl_conncache_init(&multi->conn_cache, chashsize)) goto error; multi->msglist = Curl_llist_alloc(multi_freeamsg); @@ -319,7 +312,7 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */ goto error; multi->closure_handle->multi = multi; - multi->closure_handle->state.conn_cache = multi->conn_cache; + multi->closure_handle->state.conn_cache = &multi->conn_cache; multi->max_pipeline_length = 5; @@ -329,12 +322,9 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */ error: - Curl_hash_destroy(multi->sockhash); - multi->sockhash = NULL; - Curl_hash_destroy(multi->hostcache); - multi->hostcache = NULL; - Curl_conncache_destroy(multi->conn_cache); - multi->conn_cache = NULL; + Curl_hash_destroy(&multi->sockhash); + Curl_hash_destroy(&multi->hostcache); + Curl_conncache_destroy(&multi->conn_cache); Curl_close(multi->closure_handle); multi->closure_handle = NULL; Curl_llist_destroy(multi->msglist, NULL); @@ -403,14 +393,12 @@ CURLMcode curl_multi_add_handle(CURLM *multi_handle, easy handle's one is currently not set. */ else if(!data->dns.hostcache || (data->dns.hostcachetype == HCACHE_NONE)) { - data->dns.hostcache = multi->hostcache; + data->dns.hostcache = &multi->hostcache; data->dns.hostcachetype = HCACHE_MULTI; } /* Point to the multi's connection cache */ - data->state.conn_cache = multi->conn_cache; - - data->state.infilesize = data->set.filesize; + data->state.conn_cache = &multi->conn_cache; /* This adds the new entry at the 'end' of the doubly-linked circular list of SessionHandle structs to try and maintain a FIFO queue so @@ -426,8 +414,7 @@ CURLMcode curl_multi_add_handle(CURLM *multi_handle, multi->easylp = data; /* the new last node */ } else { - /* first node, make both prev and next be NULL! */ - data->next = NULL; + /* first node, make prev NULL! */ data->prev = NULL; multi->easylp = multi->easyp = data; /* both first and last */ } @@ -487,6 +474,9 @@ CURLMcode curl_multi_remove_handle(CURLM *multi_handle, struct Curl_multi *multi=(struct Curl_multi *)multi_handle; struct SessionHandle *easy = curl_handle; struct SessionHandle *data = easy; + bool premature; + bool easy_owns_conn; + struct curl_llist_element *e; /* First, make some basic checks that the CURLM handle is a good handle */ if(!GOOD_MULTI_HANDLE(multi)) @@ -500,131 +490,127 @@ CURLMcode curl_multi_remove_handle(CURLM *multi_handle, if(!data->multi) return CURLM_OK; /* it is already removed so let's say it is fine! */ - if(easy) { - bool premature = (data->mstate < CURLM_STATE_COMPLETED) ? TRUE : FALSE; - bool easy_owns_conn = (data->easy_conn && - (data->easy_conn->data == easy)) ? - TRUE : FALSE; + premature = (data->mstate < CURLM_STATE_COMPLETED) ? TRUE : FALSE; + easy_owns_conn = (data->easy_conn && (data->easy_conn->data == easy)) ? + TRUE : FALSE; - /* If the 'state' is not INIT or COMPLETED, we might need to do something - nice to put the easy_handle in a good known state when this returns. */ - if(premature) - /* this handle is "alive" so we need to count down the total number of - alive connections when this is removed */ - multi->num_alive--; + /* If the 'state' is not INIT or COMPLETED, we might need to do something + nice to put the easy_handle in a good known state when this returns. */ + if(premature) { + /* this handle is "alive" so we need to count down the total number of + alive connections when this is removed */ + multi->num_alive--; - if(data->easy_conn && - (data->easy_conn->send_pipe->size + - data->easy_conn->recv_pipe->size > 1) && - data->mstate > CURLM_STATE_WAITDO && - data->mstate < CURLM_STATE_COMPLETED) { - /* If the handle is in a pipeline and has started sending off its - request but not received its response yet, we need to close - connection. */ - connclose(data->easy_conn, "Removed with partial response"); - /* Set connection owner so that Curl_done() closes it. - We can sefely do this here since connection is killed. */ - data->easy_conn->data = easy; - } + /* When this handle gets removed, other handles may be able to get the + connection */ + Curl_multi_process_pending_handles(multi); + } - /* The timer must be shut down before data->multi is set to NULL, - else the timenode will remain in the splay tree after - curl_easy_cleanup is called. */ - Curl_expire(data, 0); + if(data->easy_conn && + data->mstate > CURLM_STATE_DO && + data->mstate < CURLM_STATE_COMPLETED) { + /* If the handle is in a pipeline and has started sending off its + request but not received its response yet, we need to close + connection. */ + connclose(data->easy_conn, "Removed with partial response"); + /* Set connection owner so that Curl_done() closes it. + We can safely do this here since connection is killed. */ + data->easy_conn->data = easy; + easy_owns_conn = TRUE; + } - /* destroy the timeout list that is held in the easy handle */ - if(data->state.timeoutlist) { - Curl_llist_destroy(data->state.timeoutlist, NULL); - data->state.timeoutlist = NULL; - } + /* The timer must be shut down before data->multi is set to NULL, + else the timenode will remain in the splay tree after + curl_easy_cleanup is called. */ + Curl_expire(data, 0); - if(data->dns.hostcachetype == HCACHE_MULTI) { - /* stop using the multi handle's DNS cache */ - data->dns.hostcache = NULL; - data->dns.hostcachetype = HCACHE_NONE; - } + /* destroy the timeout list that is held in the easy handle */ + if(data->state.timeoutlist) { + Curl_llist_destroy(data->state.timeoutlist, NULL); + data->state.timeoutlist = NULL; + } - if(data->easy_conn) { + if(data->dns.hostcachetype == HCACHE_MULTI) { + /* stop using the multi handle's DNS cache */ + data->dns.hostcache = NULL; + data->dns.hostcachetype = HCACHE_NONE; + } - /* we must call Curl_done() here (if we still "own it") so that we don't - leave a half-baked one around */ - if(easy_owns_conn) { + if(data->easy_conn) { - /* Curl_done() clears the conn->data field to lose the association - between the easy handle and the connection + /* we must call Curl_done() here (if we still "own it") so that we don't + leave a half-baked one around */ + if(easy_owns_conn) { - Note that this ignores the return code simply because there's - nothing really useful to do with it anyway! */ - (void)Curl_done(&data->easy_conn, data->result, premature); - } - else - /* Clear connection pipelines, if Curl_done above was not called */ - Curl_getoff_all_pipelines(data, data->easy_conn); + /* Curl_done() clears the conn->data field to lose the association + between the easy handle and the connection + + Note that this ignores the return code simply because there's + nothing really useful to do with it anyway! */ + (void)Curl_done(&data->easy_conn, data->result, premature); } + else + /* Clear connection pipelines, if Curl_done above was not called */ + Curl_getoff_all_pipelines(data, data->easy_conn); + } - Curl_wildcard_dtor(&data->wildcard); + Curl_wildcard_dtor(&data->wildcard); - /* as this was using a shared connection cache we clear the pointer - to that since we're not part of that multi handle anymore */ - data->state.conn_cache = NULL; + /* as this was using a shared connection cache we clear the pointer to that + since we're not part of that multi handle anymore */ + data->state.conn_cache = NULL; - /* change state without using multistate(), only to make singlesocket() do - what we want */ - data->mstate = CURLM_STATE_COMPLETED; - singlesocket(multi, easy); /* to let the application know what sockets - that vanish with this handle */ + /* change state without using multistate(), only to make singlesocket() do + what we want */ + data->mstate = CURLM_STATE_COMPLETED; + singlesocket(multi, easy); /* to let the application know what sockets that + vanish with this handle */ - /* Remove the association between the connection and the handle */ - if(data->easy_conn) { - data->easy_conn->data = NULL; - data->easy_conn = NULL; - } + /* Remove the association between the connection and the handle */ + if(data->easy_conn) { + data->easy_conn->data = NULL; + data->easy_conn = NULL; + } - data->multi = NULL; /* clear the association to this multi handle */ + data->multi = NULL; /* clear the association to this multi handle */ - { - /* make sure there's no pending message in the queue sent from this easy - handle */ - struct curl_llist_element *e; + /* make sure there's no pending message in the queue sent from this easy + handle */ - for(e = multi->msglist->head; e; e = e->next) { - struct Curl_message *msg = e->ptr; + for(e = multi->msglist->head; e; e = e->next) { + struct Curl_message *msg = e->ptr; - if(msg->extmsg.easy_handle == easy) { - Curl_llist_remove(multi->msglist, e, NULL); - /* there can only be one from this specific handle */ - break; - } - } + if(msg->extmsg.easy_handle == easy) { + Curl_llist_remove(multi->msglist, e, NULL); + /* there can only be one from this specific handle */ + break; } + } - /* make the previous node point to our next */ - if(data->prev) - data->prev->next = data->next; - else - multi->easyp = data->next; /* point to first node */ - - /* make our next point to our previous node */ - if(data->next) - data->next->prev = data->prev; - else - multi->easylp = data->prev; /* point to last node */ + /* make the previous node point to our next */ + if(data->prev) + data->prev->next = data->next; + else + multi->easyp = data->next; /* point to first node */ - /* NOTE NOTE NOTE - We do not touch the easy handle here! */ + /* make our next point to our previous node */ + if(data->next) + data->next->prev = data->prev; + else + multi->easylp = data->prev; /* point to last node */ - multi->num_easy--; /* one less to care about now */ + /* NOTE NOTE NOTE + We do not touch the easy handle here! */ + multi->num_easy--; /* one less to care about now */ - update_timer(multi); - return CURLM_OK; - } - else - return CURLM_BAD_EASY_HANDLE; /* twasn't found */ + update_timer(multi); + return CURLM_OK; } -bool Curl_multi_pipeline_enabled(const struct Curl_multi *multi) +/* Return TRUE if the application asked for a certain set of pipelining */ +bool Curl_pipeline_wanted(const struct Curl_multi *multi, int bits) { - return (multi && multi->pipelining_enabled) ? TRUE : FALSE; + return (multi && (multi->pipelining & bits)) ? TRUE : FALSE; } void Curl_multi_handlePipeBreak(struct SessionHandle *data) @@ -650,14 +636,24 @@ static int waitconnect_getsock(struct connectdata *conn, } } + return rc; +} + +static int waitproxyconnect_getsock(struct connectdata *conn, + curl_socket_t *sock, + int numsocks) +{ + if(!numsocks) + return GETSOCK_BLANK; + + sock[0] = conn->sock[FIRSTSOCKET]; + /* 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) { - sock[0] = conn->sock[FIRSTSOCKET]; - rc = GETSOCK_READSOCK(0); - } + if(conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT) + return GETSOCK_READSOCK(0); - return rc; + return GETSOCK_WRITESOCK(0); } static int domore_getsock(struct connectdata *conn, @@ -710,6 +706,7 @@ static int multi_getsock(struct SessionHandle *data, return Curl_resolver_getsock(data->easy_conn, socks, numsocks); case CURLM_STATE_PROTOCONNECT: + case CURLM_STATE_SENDPROTOCONNECT: return Curl_protocol_getsock(data->easy_conn, socks, numsocks); case CURLM_STATE_DO: @@ -717,6 +714,8 @@ static int multi_getsock(struct SessionHandle *data, return Curl_doing_getsock(data->easy_conn, socks, numsocks); case CURLM_STATE_WAITPROXYCONNECT: + return waitproxyconnect_getsock(data->easy_conn, socks, numsocks); + case CURLM_STATE_WAITCONNECT: return waitconnect_getsock(data->easy_conn, socks, numsocks); @@ -917,12 +916,62 @@ CURLMcode curl_multi_wait(CURLM *multi_handle, else i = 0; - Curl_safefree(ufds); + free(ufds); if(ret) *ret = i; return CURLM_OK; } +/* + * Curl_multi_connchanged() is called to tell that there is a connection in + * this multi handle that has changed state (pipelining become possible, the + * number of allowed streams changed or similar), and a subsequent use of this + * multi handle should move CONNECT_PEND handles back to CONNECT to have them + * retry. + */ +void Curl_multi_connchanged(struct Curl_multi *multi) +{ + multi->recheckstate = TRUE; +} + +/* + * multi_ischanged() is called + * + * Returns TRUE/FALSE whether the state is changed to trigger a CONNECT_PEND + * => CONNECT action. + * + * Set 'clear' to TRUE to have it also clear the state variable. + */ +static bool multi_ischanged(struct Curl_multi *multi, bool clear) +{ + bool retval = multi->recheckstate; + if(clear) + multi->recheckstate = FALSE; + return retval; +} + +CURLMcode Curl_multi_add_perform(struct Curl_multi *multi, + struct SessionHandle *data, + struct connectdata *conn) +{ + CURLMcode rc; + + rc = curl_multi_add_handle(multi, data); + if(!rc) { + struct SingleRequest *k = &data->req; + + /* pass in NULL for 'conn' here since we don't want to init the + connection, only this transfer */ + Curl_init_do(data, NULL); + + /* take this handle to the perform state right away */ + multistate(data, CURLM_STATE_PERFORM); + data->easy_conn = conn; + k->keepon |= KEEP_RECV; /* setup to receive! */ + } + return rc; +} + static CURLMcode multi_runsingle(struct Curl_multi *multi, struct timeval now, struct SessionHandle *data) @@ -933,7 +982,8 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, bool protocol_connect = FALSE; bool dophase_done = FALSE; bool done = FALSE; - CURLMcode result = CURLM_OK; + CURLMcode rc; + CURLcode result = CURLE_OK; struct SingleRequest *k; long timeout_ms; int control; @@ -942,26 +992,25 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, return CURLM_BAD_EASY_HANDLE; do { - /* this is a single-iteration do-while loop just to allow a - break to skip to the end of it */ bool disconnect_conn = FALSE; + rc = CURLM_OK; /* Handle the case when the pipe breaks, i.e., the connection we're using gets cleaned up and we're left with nothing. */ if(data->state.pipe_broke) { - infof(data, "Pipe broke: handle 0x%p, url = %s\n", + infof(data, "Pipe broke: handle %p, url = %s\n", (void *)data, data->state.path); if(data->mstate < CURLM_STATE_COMPLETED) { /* Head back to the CONNECT state */ multistate(data, CURLM_STATE_CONNECT); - result = CURLM_CALL_MULTI_PERFORM; - data->result = CURLE_OK; + rc = CURLM_CALL_MULTI_PERFORM; + result = CURLE_OK; } data->state.pipe_broke = FALSE; data->easy_conn = NULL; - break; + continue; } if(!data->easy_conn && @@ -974,6 +1023,11 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, return CURLM_INTERNAL_ERROR; } + if(multi_ischanged(multi, TRUE)) { + DEBUGF(infof(data, "multi changed, check CONNECT_PEND queue!\n")); + Curl_multi_process_pending_handles(multi); + } + if(data->easy_conn && data->mstate > CURLM_STATE_CONNECT && data->mstate < CURLM_STATE_COMPLETED) /* Make sure we set the connection's current owner */ @@ -1014,26 +1068,28 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, } } - /* Force the connection closed because the server could continue to - send us stuff at any time. (The disconnect_conn logic used below - doesn't work at this point). */ - connclose(data->easy_conn, "Disconnected with pending data"); - data->result = CURLE_OPERATION_TIMEDOUT; - multistate(data, CURLM_STATE_COMPLETED); - break; + /* Force connection closed if the connection has indeed been used */ + if(data->mstate > CURLM_STATE_DO) { + connclose(data->easy_conn, "Disconnected with pending data"); + disconnect_conn = TRUE; + } + result = CURLE_OPERATION_TIMEDOUT; + (void)Curl_done(&data->easy_conn, result, TRUE); + /* Skip the statemachine and go directly to error handling section. */ + goto statemachine_end; } } switch(data->mstate) { case CURLM_STATE_INIT: /* init this transfer. */ - data->result=Curl_pretransfer(data); + result=Curl_pretransfer(data); - if(CURLE_OK == data->result) { + if(!result) { /* after init, go CONNECT */ multistate(data, CURLM_STATE_CONNECT); Curl_pgrsTime(data, TIMER_STARTOP); - result = CURLM_CALL_MULTI_PERFORM; + rc = CURLM_CALL_MULTI_PERFORM; } break; @@ -1045,25 +1101,25 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, case CURLM_STATE_CONNECT: /* Connect. We want to get a connection identifier filled in. */ Curl_pgrsTime(data, TIMER_STARTSINGLE); - data->result = Curl_connect(data, &data->easy_conn, - &async, &protocol_connect); - if(CURLE_NO_CONNECTION_AVAILABLE == data->result) { + result = Curl_connect(data, &data->easy_conn, + &async, &protocol_connect); + if(CURLE_NO_CONNECTION_AVAILABLE == result) { /* There was no connection available. We will go to the pending state and wait for an available connection. */ multistate(data, CURLM_STATE_CONNECT_PEND); /* add this handle to the list of connect-pending handles */ if(!Curl_llist_insert_next(multi->pending, multi->pending->tail, data)) - data->result = CURLE_OUT_OF_MEMORY; + result = CURLE_OUT_OF_MEMORY; else - data->result = CURLE_OK; + result = CURLE_OK; break; } - if(CURLE_OK == data->result) { + if(!result) { /* Add this handle to the send or pend pipeline */ - data->result = Curl_add_handle_to_pipeline(data, data->easy_conn); - if(CURLE_OK != data->result) + result = Curl_add_handle_to_pipeline(data, data->easy_conn); + if(result) disconnect_conn = TRUE; else { if(async) @@ -1073,10 +1129,10 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, /* after the connect has been sent off, go WAITCONNECT unless the protocol connect is already done and we can go directly to WAITDO or DO! */ - result = CURLM_CALL_MULTI_PERFORM; + rc = CURLM_CALL_MULTI_PERFORM; if(protocol_connect) - multistate(data, multi->pipelining_enabled? + multistate(data, Curl_pipeline_wanted(multi, CURLPIPE_HTTP1)? CURLM_STATE_WAITDO:CURLM_STATE_DO); else { #ifndef CURL_DISABLE_HTTP @@ -1096,31 +1152,21 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, { struct Curl_dns_entry *dns = NULL; struct connectdata *conn = data->easy_conn; - int stale; /* check if we have the name resolved by now */ - if(data->share) - Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); - - dns = Curl_fetch_addr(conn, conn->host.name, (int)conn->port, &stale); + dns = Curl_fetch_addr(conn, conn->host.name, (int)conn->port); if(dns) { - dns->inuse++; /* we use it! */ #ifdef CURLRES_ASYNCH conn->async.dns = dns; conn->async.done = TRUE; #endif - data->result = CURLRESOLV_RESOLVED; + result = CURLE_OK; infof(data, "Hostname was found in DNS cache\n"); } - if(stale) - infof(data, "Hostname in DNS cache was stale, zapped\n"); - - if(data->share) - Curl_share_unlock(data, CURL_LOCK_DATA_DNS); if(!dns) - data->result = Curl_resolver_is_resolved(data->easy_conn, &dns); + result = Curl_resolver_is_resolved(data->easy_conn, &dns); /* Update sockets here, because the socket(s) may have been closed and the application thus needs to be told, even if it @@ -1133,18 +1179,17 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, if(dns) { /* Perform the next step in the connection phase, and then move on to the WAITCONNECT state */ - data->result = Curl_async_resolved(data->easy_conn, - &protocol_connect); + result = Curl_async_resolved(data->easy_conn, &protocol_connect); - if(CURLE_OK != data->result) + if(result) /* if Curl_async_resolved() returns failure, the connection struct is already freed and gone */ data->easy_conn = NULL; /* no more connection */ else { /* call again please so that we get the next socket setup */ - result = CURLM_CALL_MULTI_PERFORM; + rc = CURLM_CALL_MULTI_PERFORM; if(protocol_connect) - multistate(data, multi->pipelining_enabled? + multistate(data, Curl_pipeline_wanted(multi, CURLPIPE_HTTP1)? CURLM_STATE_WAITDO:CURLM_STATE_DO); else { #ifndef CURL_DISABLE_HTTP @@ -1157,7 +1202,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, } } - if(CURLE_OK != data->result) { + if(result) { /* failure detected */ disconnect_conn = TRUE; break; @@ -1168,109 +1213,82 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, #ifndef CURL_DISABLE_HTTP case CURLM_STATE_WAITPROXYCONNECT: /* this is HTTP-specific, but sending CONNECT to a proxy is HTTP... */ - data->result = Curl_http_connect(data->easy_conn, &protocol_connect); + result = Curl_http_connect(data->easy_conn, &protocol_connect); + rc = CURLM_CALL_MULTI_PERFORM; if(data->easy_conn->bits.proxy_connect_closed) { /* connect back to proxy again */ - data->result = CURLE_OK; - result = CURLM_CALL_MULTI_PERFORM; + result = CURLE_OK; + Curl_done(&data->easy_conn, CURLE_OK, FALSE); multistate(data, CURLM_STATE_CONNECT); } - else if(CURLE_OK == data->result) { + else if(!result) { if(data->easy_conn->tunnel_state[FIRSTSOCKET] == TUNNEL_COMPLETE) - multistate(data, CURLM_STATE_WAITCONNECT); + /* initiate protocol connect phase */ + multistate(data, CURLM_STATE_SENDPROTOCONNECT); } break; #endif case CURLM_STATE_WAITCONNECT: - /* awaiting a completion of an asynch connect */ - data->result = Curl_is_connected(data->easy_conn, - FIRSTSOCKET, - &connected); - if(connected) { - - if(!data->result) - /* if everything is still fine we do the protocol-specific connect - setup */ - data->result = Curl_protocol_connect(data->easy_conn, - &protocol_connect); - } - - if(data->easy_conn->bits.proxy_connect_closed) { - /* connect back to proxy again since it was closed in a proxy CONNECT - setup */ - data->result = CURLE_OK; - result = CURLM_CALL_MULTI_PERFORM; - multistate(data, CURLM_STATE_CONNECT); - break; + /* awaiting a completion of an asynch TCP connect */ + result = Curl_is_connected(data->easy_conn, FIRSTSOCKET, &connected); + if(connected && !result) { + rc = CURLM_CALL_MULTI_PERFORM; + multistate(data, data->easy_conn->bits.tunnel_proxy? + CURLM_STATE_WAITPROXYCONNECT: + CURLM_STATE_SENDPROTOCONNECT); } - else if(CURLE_OK != data->result) { + else if(result) { /* failure detected */ /* Just break, the cleaning up is handled all in one place */ disconnect_conn = TRUE; break; } + break; - if(connected) { - if(!protocol_connect) { - /* We have a TCP connection, but 'protocol_connect' may be false - and then we continue to 'STATE_PROTOCONNECT'. If protocol - connect is TRUE, we move on to STATE_DO. - BUT if we are using a proxy we must change to WAITPROXYCONNECT - */ -#ifndef CURL_DISABLE_HTTP - if(data->easy_conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT) - multistate(data, CURLM_STATE_WAITPROXYCONNECT); - else -#endif - multistate(data, CURLM_STATE_PROTOCONNECT); - - } - else - /* after the connect has completed, go WAITDO or DO */ - multistate(data, multi->pipelining_enabled? - CURLM_STATE_WAITDO:CURLM_STATE_DO); - - result = CURLM_CALL_MULTI_PERFORM; + case CURLM_STATE_SENDPROTOCONNECT: + result = Curl_protocol_connect(data->easy_conn, &protocol_connect); + if(!protocol_connect) + /* switch to waiting state */ + multistate(data, CURLM_STATE_PROTOCONNECT); + else if(!result) { + /* protocol connect has completed, go WAITDO or DO */ + multistate(data, Curl_pipeline_wanted(multi, CURLPIPE_HTTP1)? + CURLM_STATE_WAITDO:CURLM_STATE_DO); + rc = CURLM_CALL_MULTI_PERFORM; + } + else if(result) { + /* failure detected */ + Curl_posttransfer(data); + Curl_done(&data->easy_conn, result, TRUE); + disconnect_conn = TRUE; } break; case CURLM_STATE_PROTOCONNECT: /* protocol-specific connect phase */ - data->result = Curl_protocol_connecting(data->easy_conn, - &protocol_connect); - if((data->result == CURLE_OK) && protocol_connect) { + result = Curl_protocol_connecting(data->easy_conn, &protocol_connect); + if(!result && protocol_connect) { /* after the connect has completed, go WAITDO or DO */ - multistate(data, multi->pipelining_enabled? + multistate(data, Curl_pipeline_wanted(multi, CURLPIPE_HTTP1)? CURLM_STATE_WAITDO:CURLM_STATE_DO); - result = CURLM_CALL_MULTI_PERFORM; + rc = CURLM_CALL_MULTI_PERFORM; } - else if(data->result) { + else if(result) { /* failure detected */ Curl_posttransfer(data); - Curl_done(&data->easy_conn, data->result, TRUE); + Curl_done(&data->easy_conn, result, TRUE); disconnect_conn = TRUE; } break; case CURLM_STATE_WAITDO: /* Wait for our turn to DO when we're pipelining requests */ -#ifdef DEBUGBUILD - infof(data, "WAITDO: Conn %ld send pipe %zu inuse %s athead %s\n", - data->easy_conn->connection_id, - data->easy_conn->send_pipe->size, - data->easy_conn->writechannel_inuse?"TRUE":"FALSE", - isHandleAtHead(data, - data->easy_conn->send_pipe)?"TRUE":"FALSE"); -#endif - if(!data->easy_conn->writechannel_inuse && - isHandleAtHead(data, - data->easy_conn->send_pipe)) { - /* Grab the channel */ - data->easy_conn->writechannel_inuse = TRUE; + if(Curl_pipeline_checkget_write(data, data->easy_conn)) { + /* Grabbed the channel */ multistate(data, CURLM_STATE_DO); - result = CURLM_CALL_MULTI_PERFORM; + rc = CURLM_CALL_MULTI_PERFORM; } break; @@ -1279,16 +1297,16 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, /* keep connection open for application to use the socket */ connkeep(data->easy_conn, "CONNECT_ONLY"); multistate(data, CURLM_STATE_DONE); - data->result = CURLE_OK; - result = CURLM_CALL_MULTI_PERFORM; + result = CURLE_OK; + rc = CURLM_CALL_MULTI_PERFORM; } else { /* Perform the protocol's DO action */ - data->result = Curl_do(&data->easy_conn, &dophase_done); + result = Curl_do(&data->easy_conn, &dophase_done); /* When Curl_do() returns failure, data->easy_conn might be NULL! */ - if(CURLE_OK == data->result) { + if(!result) { if(!dophase_done) { /* some steps needed for wildcard matching */ if(data->set.wildcardmatch) { @@ -1297,14 +1315,14 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, /* skip some states if it is important */ Curl_done(&data->easy_conn, CURLE_OK, FALSE); multistate(data, CURLM_STATE_DONE); - result = CURLM_CALL_MULTI_PERFORM; + rc = CURLM_CALL_MULTI_PERFORM; break; } } /* DO was not completed in one function call, we must continue DOING... */ multistate(data, CURLM_STATE_DOING); - result = CURLM_OK; + rc = CURLM_OK; } /* after DO, go DO_DONE... or DO_MORE */ @@ -1312,15 +1330,15 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, /* we're supposed to do more, but we need to sit down, relax and wait a little while first */ multistate(data, CURLM_STATE_DO_MORE); - result = CURLM_OK; + rc = CURLM_OK; } else { /* we're done with the DO, now DO_DONE */ multistate(data, CURLM_STATE_DO_DONE); - result = CURLM_CALL_MULTI_PERFORM; + rc = CURLM_CALL_MULTI_PERFORM; } } - else if((CURLE_SEND_ERROR == data->result) && + else if((CURLE_SEND_ERROR == result) && data->easy_conn->bits.reuse) { /* * In this situation, a connection that we were trying to use @@ -1335,48 +1353,49 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, drc = Curl_retry_request(data->easy_conn, &newurl); if(drc) { /* a failure here pretty much implies an out of memory */ - data->result = drc; + result = drc; disconnect_conn = TRUE; } else retry = (newurl)?TRUE:FALSE; Curl_posttransfer(data); - drc = Curl_done(&data->easy_conn, data->result, FALSE); + drc = Curl_done(&data->easy_conn, result, FALSE); /* When set to retry the connection, we must to go back to * the CONNECT state */ if(retry) { - if((drc == CURLE_OK) || (drc == CURLE_SEND_ERROR)) { + if(!drc || (drc == CURLE_SEND_ERROR)) { follow = FOLLOW_RETRY; drc = Curl_follow(data, newurl, follow); - if(drc == CURLE_OK) { + if(!drc) { multistate(data, CURLM_STATE_CONNECT); - result = CURLM_CALL_MULTI_PERFORM; - data->result = CURLE_OK; + rc = CURLM_CALL_MULTI_PERFORM; + result = CURLE_OK; } else { /* Follow failed */ - data->result = drc; + result = drc; free(newurl); } } else { /* done didn't return OK or SEND_ERROR */ - data->result = drc; + result = drc; free(newurl); } } else { /* Have error handler disconnect conn if we can't retry */ disconnect_conn = TRUE; + free(newurl); } } else { /* failure detected */ Curl_posttransfer(data); if(data->easy_conn) - Curl_done(&data->easy_conn, data->result, FALSE); + Curl_done(&data->easy_conn, result, FALSE); disconnect_conn = TRUE; } } @@ -1384,21 +1403,21 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, case CURLM_STATE_DOING: /* we continue DOING until the DO phase is complete */ - data->result = Curl_protocol_doing(data->easy_conn, - &dophase_done); - if(CURLE_OK == data->result) { + result = Curl_protocol_doing(data->easy_conn, + &dophase_done); + if(!result) { if(dophase_done) { /* after DO, go DO_DONE or DO_MORE */ multistate(data, data->easy_conn->bits.do_more? CURLM_STATE_DO_MORE: CURLM_STATE_DO_DONE); - result = CURLM_CALL_MULTI_PERFORM; + rc = CURLM_CALL_MULTI_PERFORM; } /* dophase_done */ } else { /* failure detected */ Curl_posttransfer(data); - Curl_done(&data->easy_conn, data->result, FALSE); + Curl_done(&data->easy_conn, result, FALSE); disconnect_conn = TRUE; } break; @@ -1407,27 +1426,27 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, /* * When we are connected, DO MORE and then go DO_DONE */ - data->result = Curl_do_more(data->easy_conn, &control); + result = Curl_do_more(data->easy_conn, &control); /* No need to remove this handle from the send pipeline here since that is done in Curl_done() */ - if(CURLE_OK == data->result) { + if(!result) { if(control) { /* if positive, advance to DO_DONE if negative, go back to DOING */ multistate(data, control==1? CURLM_STATE_DO_DONE: CURLM_STATE_DOING); - result = CURLM_CALL_MULTI_PERFORM; + rc = CURLM_CALL_MULTI_PERFORM; } else /* stay in DO_MORE */ - result = CURLM_OK; + rc = CURLM_OK; } else { /* failure detected */ Curl_posttransfer(data); - Curl_done(&data->easy_conn, data->result, FALSE); + Curl_done(&data->easy_conn, result, FALSE); disconnect_conn = TRUE; } break; @@ -1445,37 +1464,24 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, multistate(data, CURLM_STATE_WAITPERFORM); else multistate(data, CURLM_STATE_DONE); - result = CURLM_CALL_MULTI_PERFORM; + rc = CURLM_CALL_MULTI_PERFORM; break; case CURLM_STATE_WAITPERFORM: /* Wait for our turn to PERFORM */ - if(!data->easy_conn->readchannel_inuse && - isHandleAtHead(data, - data->easy_conn->recv_pipe)) { - /* Grab the channel */ - data->easy_conn->readchannel_inuse = TRUE; + if(Curl_pipeline_checkget_read(data, data->easy_conn)) { + /* Grabbed the channel */ multistate(data, CURLM_STATE_PERFORM); - result = CURLM_CALL_MULTI_PERFORM; + rc = CURLM_CALL_MULTI_PERFORM; } -#ifdef DEBUGBUILD - else { - infof(data, "WAITPERFORM: Conn %ld recv pipe %zu inuse %s athead %s\n", - data->easy_conn->connection_id, - data->easy_conn->recv_pipe->size, - data->easy_conn->readchannel_inuse?"TRUE":"FALSE", - isHandleAtHead(data, - data->easy_conn->recv_pipe)?"TRUE":"FALSE"); - } -#endif break; case CURLM_STATE_TOOFAST: /* limit-rate exceeded in either direction */ /* if both rates are within spec, resume transfer */ if(Curl_pgrsUpdate(data->easy_conn)) - data->result = CURLE_ABORTED_BY_CALLBACK; + result = CURLE_ABORTED_BY_CALLBACK; else - data->result = Curl_speedcheck(data, now); + result = Curl_speedcheck(data, now); if(( (data->set.max_send_speed == 0) || (data->progress.ulspeed < data->set.max_send_speed )) && @@ -1485,7 +1491,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, break; case CURLM_STATE_PERFORM: - { + { char *newurl = NULL; bool retry = FALSE; @@ -1512,7 +1518,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, multistate(data, CURLM_STATE_TOOFAST); - /* Calculate download rate-limitation timeout. */ + /* Calculate download rate-limitation timeout. */ buffersize = (int)(data->set.buffer_size ? data->set.buffer_size : BUFSIZE); timeout_ms = Curl_sleep_time(data->set.max_recv_speed, @@ -1522,21 +1528,19 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, } /* read/write data if it is ready to do so */ - data->result = Curl_readwrite(data->easy_conn, &done); + result = Curl_readwrite(data->easy_conn, data, &done); k = &data->req; - if(!(k->keepon & KEEP_RECV)) { + if(!(k->keepon & KEEP_RECV)) /* We're done receiving */ - data->easy_conn->readchannel_inuse = FALSE; - } + Curl_pipeline_leave_read(data->easy_conn); - if(!(k->keepon & KEEP_SEND)) { + if(!(k->keepon & KEEP_SEND)) /* We're done sending */ - data->easy_conn->writechannel_inuse = FALSE; - } + Curl_pipeline_leave_write(data->easy_conn); - if(done || (data->result == CURLE_RECV_ERROR)) { + if(done || (result == CURLE_RECV_ERROR)) { /* If CURLE_RECV_ERROR happens early enough, we assume it was a race * condition and the server closed the re-used connection exactly when * we wanted to use it, so figure out if that is indeed the case. @@ -1548,12 +1552,12 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, if(retry) { /* if we are to retry, set the result to OK and consider the request as done */ - data->result = CURLE_OK; + result = CURLE_OK; done = TRUE; } } - if(data->result) { + if(result) { /* * The transfer phase returned error, we mark the connection to get * closed to prevent being re-used. This is because we can't possibly @@ -1566,7 +1570,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, connclose(data->easy_conn, "Transfer returned error"); Curl_posttransfer(data); - Curl_done(&data->easy_conn, data->result, FALSE); + Curl_done(&data->easy_conn, result, FALSE); } else if(done) { followtype follow=FOLLOW_NONE; @@ -1590,18 +1594,19 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, if(!retry) { /* if the URL is a follow-location and not just a retried request then figure out the URL here */ + free(newurl); newurl = data->req.newurl; data->req.newurl = NULL; follow = FOLLOW_REDIR; } else follow = FOLLOW_RETRY; - data->result = Curl_done(&data->easy_conn, CURLE_OK, FALSE); - if(CURLE_OK == data->result) { - data->result = Curl_follow(data, newurl, follow); - if(CURLE_OK == data->result) { + result = Curl_done(&data->easy_conn, CURLE_OK, FALSE); + if(!result) { + result = Curl_follow(data, newurl, follow); + if(!result) { multistate(data, CURLM_STATE_CONNECT); - result = CURLM_CALL_MULTI_PERFORM; + rc = CURLM_CALL_MULTI_PERFORM; newurl = NULL; /* handed over the memory ownership to Curl_follow(), make sure we don't free() it here */ @@ -1614,30 +1619,28 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, /* but first check to see if we got a location info even though we're not following redirects */ if(data->req.location) { - if(newurl) - free(newurl); + free(newurl); newurl = data->req.location; data->req.location = NULL; - data->result = Curl_follow(data, newurl, FOLLOW_FAKE); - if(CURLE_OK == data->result) + result = Curl_follow(data, newurl, FOLLOW_FAKE); + if(!result) newurl = NULL; /* allocation was handed over Curl_follow() */ else disconnect_conn = TRUE; } multistate(data, CURLM_STATE_DONE); - result = CURLM_CALL_MULTI_PERFORM; + rc = CURLM_CALL_MULTI_PERFORM; } } - if(newurl) - free(newurl); + free(newurl); break; - } + } case CURLM_STATE_DONE: /* this state is highly transient, so run another loop after this */ - result = CURLM_CALL_MULTI_PERFORM; + rc = CURLM_CALL_MULTI_PERFORM; if(data->easy_conn) { CURLcode res; @@ -1648,11 +1651,11 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, Curl_multi_process_pending_handles(multi); /* post-transfer command */ - res = Curl_done(&data->easy_conn, data->result, FALSE); + res = Curl_done(&data->easy_conn, result, FALSE); /* allow a previously set error code take precedence */ - if(!data->result) - data->result = res; + if(!result) + result = res; /* * If there are other handles on the pipeline, Curl_done won't set @@ -1692,14 +1695,16 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, break; case CURLM_STATE_MSGSENT: + data->result = result; return CURLM_OK; /* do nothing */ default: return CURLM_INTERNAL_ERROR; } + statemachine_end: if(data->mstate < CURLM_STATE_COMPLETED) { - if(CURLE_OK != data->result) { + if(result) { /* * If an error was returned, and we aren't in completed state now, * then we go to completed and consider this transfer aborted. @@ -1710,20 +1715,21 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, data->state.pipe_broke = FALSE; + /* Check if we can move pending requests to send pipe */ + Curl_multi_process_pending_handles(multi); + if(data->easy_conn) { /* if this has a connection, unsubscribe from the pipelines */ - data->easy_conn->writechannel_inuse = FALSE; - data->easy_conn->readchannel_inuse = FALSE; - Curl_removeHandleFromPipeline(data, - data->easy_conn->send_pipe); - Curl_removeHandleFromPipeline(data, - data->easy_conn->recv_pipe); - /* Check if we can move pending requests to send pipe */ - Curl_multi_process_pending_handles(multi); + Curl_pipeline_leave_write(data->easy_conn); + Curl_pipeline_leave_read(data->easy_conn); + Curl_removeHandleFromPipeline(data, data->easy_conn->send_pipe); + Curl_removeHandleFromPipeline(data, data->easy_conn->recv_pipe); if(disconnect_conn) { + /* Don't attempt to send data over a connection that timed out */ + bool dead_connection = result == CURLE_OPERATION_TIMEDOUT; /* disconnect properly */ - Curl_disconnect(data->easy_conn, /* dead_connection */ FALSE); + Curl_disconnect(data->easy_conn, dead_connection); /* This is where we make sure that the easy_conn pointer is reset. We don't have to do this in every case block above where a @@ -1742,31 +1748,34 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, else if(data->easy_conn && Curl_pgrsUpdate(data->easy_conn)) { /* aborted due to progress callback return code must close the connection */ - data->result = CURLE_ABORTED_BY_CALLBACK; + result = CURLE_ABORTED_BY_CALLBACK; connclose(data->easy_conn, "Aborted by callback"); /* if not yet in DONE state, go there, otherwise COMPLETED */ multistate(data, (data->mstate < CURLM_STATE_DONE)? CURLM_STATE_DONE: CURLM_STATE_COMPLETED); - result = CURLM_CALL_MULTI_PERFORM; + rc = CURLM_CALL_MULTI_PERFORM; } } - } WHILE_FALSE; /* just to break out from! */ - if(CURLM_STATE_COMPLETED == data->mstate) { - /* now fill in the Curl_message with this info */ - msg = &data->msg; + if(CURLM_STATE_COMPLETED == data->mstate) { + /* now fill in the Curl_message with this info */ + msg = &data->msg; - msg->extmsg.msg = CURLMSG_DONE; - msg->extmsg.easy_handle = data; - msg->extmsg.data.result = data->result; + msg->extmsg.msg = CURLMSG_DONE; + msg->extmsg.easy_handle = data; + msg->extmsg.data.result = result; - result = multi_addmsg(multi, msg); + rc = multi_addmsg(multi, msg); - multistate(data, CURLM_STATE_MSGSENT); - } + multistate(data, CURLM_STATE_MSGSENT); + } + } while((rc == CURLM_CALL_MULTI_PERFORM) || multi_ischanged(multi, FALSE)); - return result; + data->result = result; + + + return rc; } @@ -1796,9 +1805,7 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles) } sigpipe_ignore(data, &pipe_st); - do - result = multi_runsingle(multi, now, data); - while(CURLM_CALL_MULTI_PERFORM == result); + result = multi_runsingle(multi, now, data); sigpipe_restore(&pipe_st); if(data->set.wildcardmatch) { @@ -1843,7 +1850,7 @@ static void close_all_connections(struct Curl_multi *multi) { struct connectdata *conn; - conn = Curl_conncache_find_first_connection(multi->conn_cache); + conn = Curl_conncache_find_first_connection(&multi->conn_cache); while(conn) { SIGPIPE_VARIABLE(pipe_st); conn->data = multi->closure_handle; @@ -1853,7 +1860,7 @@ static void close_all_connections(struct Curl_multi *multi) (void)Curl_disconnect(conn, FALSE); sigpipe_restore(&pipe_st); - conn = Curl_conncache_find_first_connection(multi->conn_cache); + conn = Curl_conncache_find_first_connection(&multi->conn_cache); } } @@ -1876,15 +1883,15 @@ CURLMcode curl_multi_cleanup(CURLM *multi_handle) sigpipe_ignore(multi->closure_handle, &pipe_st); restore_pipe = TRUE; - multi->closure_handle->dns.hostcache = multi->hostcache; + multi->closure_handle->dns.hostcache = &multi->hostcache; Curl_hostcache_clean(multi->closure_handle, multi->closure_handle->dns.hostcache); Curl_close(multi->closure_handle); } - Curl_hash_destroy(multi->sockhash); - Curl_conncache_destroy(multi->conn_cache); + Curl_hash_destroy(&multi->sockhash); + Curl_conncache_destroy(&multi->conn_cache); Curl_llist_destroy(multi->msglist, NULL); Curl_llist_destroy(multi->pending, NULL); @@ -1906,7 +1913,7 @@ CURLMcode curl_multi_cleanup(CURLM *multi_handle) data = nextdata; } - Curl_hash_destroy(multi->hostcache); + Curl_hash_destroy(&multi->hostcache); /* Free the blacklists by setting them to NULL */ Curl_pipeline_set_site_blacklist(NULL, &multi->pipelining_site_bl); @@ -1995,7 +2002,7 @@ static void singlesocket(struct Curl_multi *multi, s = socks[i]; /* get it from the hash */ - entry = Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(s)); + entry = Curl_hash_pick(&multi->sockhash, (char *)&s, sizeof(s)); if(curraction & GETSOCK_READSOCK(i)) action |= CURL_POLL_IN; @@ -2010,7 +2017,7 @@ static void singlesocket(struct Curl_multi *multi, } else { /* this is a socket we didn't have before, add it! */ - entry = sh_addentry(multi->sockhash, s, data); + entry = sh_addentry(&multi->sockhash, s, data); if(!entry) /* fatal */ return; @@ -2046,7 +2053,7 @@ static void singlesocket(struct Curl_multi *multi, /* this socket has been removed. Tell the app to remove it */ remove_sock_from_hash = TRUE; - entry = Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(s)); + entry = Curl_hash_pick(&multi->sockhash, (char *)&s, sizeof(s)); if(entry) { /* check if the socket to be removed serves a connection which has other easy-s in a pipeline. In this case the socket should not be @@ -2061,7 +2068,7 @@ static void singlesocket(struct Curl_multi *multi, for the recv_pipe, or the first (in case this particular easy isn't already) */ if(entry->easy == data) { - if(isHandleAtHead(data, easy_conn->recv_pipe)) + if(Curl_recvpipe_head(data, easy_conn)) entry->easy = easy_conn->recv_pipe->head->next->ptr; else entry->easy = easy_conn->recv_pipe->head->ptr; @@ -2075,7 +2082,7 @@ static void singlesocket(struct Curl_multi *multi, for the send_pipe, or the first (in case this particular easy isn't already) */ if(entry->easy == data) { - if(isHandleAtHead(data, easy_conn->send_pipe)) + if(Curl_sendpipe_head(data, easy_conn)) entry->easy = easy_conn->send_pipe->head->next->ptr; else entry->easy = easy_conn->send_pipe->head->ptr; @@ -2101,7 +2108,7 @@ static void singlesocket(struct Curl_multi *multi, CURL_POLL_REMOVE, multi->socket_userp, entry->socketp); - sh_delentry(multi->sockhash, s); + sh_delentry(&multi->sockhash, s); } } @@ -2115,7 +2122,7 @@ static void singlesocket(struct Curl_multi *multi, * Curl_multi_closed() * * Used by the connect code to tell the multi_socket code that one of the - * sockets we were using have just been closed. This function will then + * sockets we were using is about to be closed. This function will then * remove it from the sockethash for this handle to make the multi_socket API * behave properly, especially for the case when libcurl will create another * socket again and it gets the same file descriptor number. @@ -2128,7 +2135,7 @@ void Curl_multi_closed(struct connectdata *conn, curl_socket_t s) /* this is set if this connection is part of a handle that is added to a multi handle, and only then this is necessary */ struct Curl_sh_entry *entry = - Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(s)); + Curl_hash_pick(&multi->sockhash, (char *)&s, sizeof(s)); if(entry) { if(multi->socket_cb) @@ -2137,7 +2144,7 @@ void Curl_multi_closed(struct connectdata *conn, curl_socket_t s) entry->socketp); /* now remove it from the socket hash */ - sh_delentry(multi->sockhash, s); + sh_delentry(&multi->sockhash, s); } } } @@ -2230,7 +2237,7 @@ static CURLMcode multi_socket(struct Curl_multi *multi, else if(s != CURL_SOCKET_TIMEOUT) { struct Curl_sh_entry *entry = - Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(s)); + Curl_hash_pick(&multi->sockhash, (char *)&s, sizeof(s)); if(!entry) /* Unmatched socket, we can't act on it but we ignore this fact. In @@ -2268,9 +2275,7 @@ static CURLMcode multi_socket(struct Curl_multi *multi, data->easy_conn->cselect_bits = ev_bitmask; sigpipe_ignore(data, &pipe_st); - do - result = multi_runsingle(multi, now, data); - while(CURLM_CALL_MULTI_PERFORM == result); + result = multi_runsingle(multi, now, data); sigpipe_restore(&pipe_st); if(data->easy_conn && @@ -2312,9 +2317,7 @@ static CURLMcode multi_socket(struct Curl_multi *multi, SIGPIPE_VARIABLE(pipe_st); sigpipe_ignore(data, &pipe_st); - do - result = multi_runsingle(multi, now, data); - while(CURLM_CALL_MULTI_PERFORM == result); + result = multi_runsingle(multi, now, data); sigpipe_restore(&pipe_st); if(CURLM_OK >= result) @@ -2358,8 +2361,14 @@ CURLMcode curl_multi_setopt(CURLM *multi_handle, case CURLMOPT_SOCKETDATA: multi->socket_userp = va_arg(param, void *); break; + case CURLMOPT_PUSHFUNCTION: + multi->push_cb = va_arg(param, curl_push_callback); + break; + case CURLMOPT_PUSHDATA: + multi->push_userp = va_arg(param, void *); + break; case CURLMOPT_PIPELINING: - multi->pipelining_enabled = (0 != va_arg(param, long)) ? TRUE : FALSE; + multi->pipelining = va_arg(param, long); break; case CURLMOPT_TIMERFUNCTION: multi->timer_cb = va_arg(param, curl_multi_timer_callback); @@ -2437,7 +2446,7 @@ CURLMcode curl_multi_socket_all(CURLM *multi_handle, int *running_handles) static CURLMcode multi_timeout(struct Curl_multi *multi, long *timeout_ms) { - static struct timeval tv_zero = {0,0}; + static struct timeval tv_zero = {0, 0}; if(multi->timetree) { /* we have a tree of expire times */ @@ -2495,7 +2504,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 timeval 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 @@ -2517,22 +2526,6 @@ static int update_timer(struct Curl_multi *multi) return multi->timer_cb((CURLM*)multi, timeout_ms, multi->timer_userp); } -void Curl_multi_set_easy_connection(struct SessionHandle *handle, - struct connectdata *conn) -{ - handle->easy_conn = conn; -} - -static bool isHandleAtHead(struct SessionHandle *handle, - struct curl_llist *pipeline) -{ - struct curl_llist_element *curr = pipeline->head; - if(curr) - return (curr->ptr == handle) ? TRUE : FALSE; - - return FALSE; -} - /* * multi_freetimeout() * @@ -2698,24 +2691,24 @@ void Curl_expire(struct SessionHandle *data, long milli) */ void Curl_expire_latest(struct SessionHandle *data, long milli) { - struct timeval *exp = &data->state.expiretime; + struct timeval *expire = &data->state.expiretime; struct timeval set; set = Curl_tvnow(); - set.tv_sec += milli/1000; - set.tv_usec += (milli%1000)*1000; + set.tv_sec += milli / 1000; + set.tv_usec += (milli % 1000) * 1000; if(set.tv_usec >= 1000000) { set.tv_sec++; set.tv_usec -= 1000000; } - if(exp->tv_sec || exp->tv_usec) { + if(expire->tv_sec || expire->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. */ - long diff = curlx_tvdiff(set, *exp); + long diff = curlx_tvdiff(set, *expire); if(diff > 0) /* the new expire time was later than the top time, so just skip this */ return; @@ -2732,7 +2725,8 @@ CURLMcode curl_multi_assign(CURLM *multi_handle, struct Curl_multi *multi = (struct Curl_multi *)multi_handle; if(s != CURL_SOCKET_BAD) - there = Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(curl_socket_t)); + there = Curl_hash_pick(&multi->sockhash, (char *)&s, + sizeof(curl_socket_t)); if(!there) return CURLM_BAD_SOCKET; @@ -2752,11 +2746,6 @@ size_t Curl_multi_max_total_connections(struct Curl_multi *multi) return multi ? multi->max_total_connections : 0; } -size_t Curl_multi_max_pipeline_length(struct Curl_multi *multi) -{ - return multi ? multi->max_pipeline_length : 0; -} - curl_off_t Curl_multi_content_length_penalty_size(struct Curl_multi *multi) { return multi ? multi->content_length_penalty_size : 0; @@ -2816,7 +2805,7 @@ void Curl_multi_dump(const struct Curl_multi *multi_handle) for(i=0; i < data->numsocks; i++) { curl_socket_t s = data->sockets[i]; struct Curl_sh_entry *entry = - Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(s)); + Curl_hash_pick(&multi->sockhash, (char *)&s, sizeof(s)); fprintf(stderr, "%d ", (int)s); if(!entry) { diff --git a/Utilities/cmcurl/lib/multihandle.h b/Utilities/cmcurl/lib/multihandle.h index 1a4b1d9..6c24f50 100644 --- a/Utilities/cmcurl/lib/multihandle.h +++ b/Utilities/cmcurl/lib/multihandle.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -22,6 +22,8 @@ * ***************************************************************************/ +#include "conncache.h" + struct Curl_message { /* the 'CURLMsg' is the part that is visible to the external user */ struct CURLMsg extmsg; @@ -35,22 +37,23 @@ typedef enum { CURLM_STATE_CONNECT_PEND, /* 1 - no connections, waiting for one */ CURLM_STATE_CONNECT, /* 2 - resolve/connect has been sent off */ CURLM_STATE_WAITRESOLVE, /* 3 - awaiting the resolve to finalize */ - CURLM_STATE_WAITCONNECT, /* 4 - awaiting the connect to finalize */ + CURLM_STATE_WAITCONNECT, /* 4 - awaiting the TCP connect to finalize */ CURLM_STATE_WAITPROXYCONNECT, /* 5 - awaiting proxy CONNECT to finalize */ - CURLM_STATE_PROTOCONNECT, /* 6 - completing the protocol-specific connect + CURLM_STATE_SENDPROTOCONNECT, /* 6 - initiate protocol connect procedure */ + CURLM_STATE_PROTOCONNECT, /* 7 - completing the protocol-specific connect phase */ - CURLM_STATE_WAITDO, /* 7 - wait for our turn to send the request */ - CURLM_STATE_DO, /* 8 - start send off the request (part 1) */ - CURLM_STATE_DOING, /* 9 - sending off the request (part 1) */ - CURLM_STATE_DO_MORE, /* 10 - send off the request (part 2) */ - CURLM_STATE_DO_DONE, /* 11 - done sending off request */ - CURLM_STATE_WAITPERFORM, /* 12 - wait for our turn to read the response */ - CURLM_STATE_PERFORM, /* 13 - transfer data */ - CURLM_STATE_TOOFAST, /* 14 - wait because limit-rate exceeded */ - CURLM_STATE_DONE, /* 15 - post data transfer operation */ - CURLM_STATE_COMPLETED, /* 16 - operation complete */ - CURLM_STATE_MSGSENT, /* 17 - the operation complete message is sent */ - CURLM_STATE_LAST /* 18 - not a true state, never use this */ + CURLM_STATE_WAITDO, /* 8 - wait for our turn to send the request */ + CURLM_STATE_DO, /* 9 - start send off the request (part 1) */ + CURLM_STATE_DOING, /* 10 - sending off the request (part 1) */ + CURLM_STATE_DO_MORE, /* 11 - send off the request (part 2) */ + CURLM_STATE_DO_DONE, /* 12 - done sending off request */ + CURLM_STATE_WAITPERFORM, /* 13 - wait for our turn to read the response */ + CURLM_STATE_PERFORM, /* 14 - transfer data */ + CURLM_STATE_TOOFAST, /* 15 - wait because limit-rate exceeded */ + CURLM_STATE_DONE, /* 16 - post data transfer operation */ + CURLM_STATE_COMPLETED, /* 17 - operation complete */ + CURLM_STATE_MSGSENT, /* 18 - the operation complete message is sent */ + CURLM_STATE_LAST /* 19 - not a true state, never use this */ } CURLMstate; /* we support N sockets per easy handle. Set the corresponding bit to what @@ -59,6 +62,8 @@ typedef enum { #define GETSOCK_READABLE (0x00ff) #define GETSOCK_WRITABLE (0xff00) +#define CURLPIPE_ANY (CURLPIPE_HTTP1 | CURLPIPE_MULTIPLEX) + /* This is the struct known as CURLM on the outside */ struct Curl_multi { /* First a simple identifier to easier detect if a user mix up @@ -82,8 +87,12 @@ struct Curl_multi { curl_socket_callback socket_cb; void *socket_userp; + /* callback function and user data pointer for server push */ + curl_push_callback push_cb; + void *push_userp; + /* Hostname cache */ - struct curl_hash *hostcache; + struct curl_hash hostcache; /* timetree points to the splay-tree of time nodes to figure out expire times of all currently set timers */ @@ -92,13 +101,15 @@ struct Curl_multi { /* 'sockhash' is the lookup hash for socket descriptor => easy handles (note the pluralis form, there can be more than one easy handle waiting on the same actual socket) */ - struct curl_hash *sockhash; + struct curl_hash sockhash; - /* Whether pipelining is enabled for this multi handle */ - bool pipelining_enabled; + /* pipelining wanted bits (CURLPIPE*) */ + long pipelining; + + bool recheckstate; /* see Curl_multi_connchanged */ /* Shared connection cache (bundles)*/ - struct conncache *conn_cache; + struct conncache conn_cache; /* This handle will be used for closing the cached connections in curl_multi_cleanup() */ @@ -139,4 +150,3 @@ struct Curl_multi { }; #endif /* HEADER_CURL_MULTIHANDLE_H */ - diff --git a/Utilities/cmcurl/lib/multiif.h b/Utilities/cmcurl/lib/multiif.h index c77b3ca..e6323ad 100644 --- a/Utilities/cmcurl/lib/multiif.h +++ b/Utilities/cmcurl/lib/multiif.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -27,8 +27,7 @@ */ void Curl_expire(struct SessionHandle *data, long milli); void Curl_expire_latest(struct SessionHandle *data, long milli); - -bool Curl_multi_pipeline_enabled(const struct Curl_multi* multi); +bool Curl_pipeline_wanted(const struct Curl_multi* multi, int bits); void Curl_multi_handlePipeBreak(struct SessionHandle *data); /* Internal version of curl_multi_init() accepts size parameters for the @@ -55,18 +54,11 @@ struct Curl_multi *Curl_multi_handle(int hashsize, int chashsize); void Curl_multi_dump(const struct Curl_multi *multi_handle); #endif -/* Update the current connection of a One_Easy handle */ -void Curl_multi_set_easy_connection(struct SessionHandle *handle, - struct connectdata *conn); - void Curl_multi_process_pending_handles(struct Curl_multi *multi); /* Return the value of the CURLMOPT_MAX_HOST_CONNECTIONS option */ size_t Curl_multi_max_host_connections(struct Curl_multi *multi); -/* Return the value of the CURLMOPT_MAX_PIPELINE_LENGTH option */ -size_t Curl_multi_max_pipeline_length(struct Curl_multi *multi); - /* Return the value of the CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE option */ curl_off_t Curl_multi_content_length_penalty_size(struct Curl_multi *multi); @@ -82,11 +74,13 @@ struct curl_llist *Curl_multi_pipelining_server_bl(struct Curl_multi *multi); /* Return the value of the CURLMOPT_MAX_TOTAL_CONNECTIONS option */ size_t Curl_multi_max_total_connections(struct Curl_multi *multi); +void Curl_multi_connchanged(struct Curl_multi *multi); + /* * Curl_multi_closed() * * Used by the connect code to tell the multi_socket code that one of the - * sockets we were using have just been closed. This function will then + * sockets we were using is about to be closed. This function will then * remove it from the sockethash for this handle to make the multi_socket API * behave properly, especially for the case when libcurl will create another * socket again and it gets the same file descriptor number. @@ -94,4 +88,10 @@ size_t Curl_multi_max_total_connections(struct Curl_multi *multi); void Curl_multi_closed(struct connectdata *conn, curl_socket_t s); +/* + * Add a handle and move it into PERFORM state at once. For pushed streams. + */ +CURLMcode Curl_multi_add_perform(struct Curl_multi *multi, + struct SessionHandle *data, + struct connectdata *conn); #endif /* HEADER_CURL_MULTIIF_H */ diff --git a/Utilities/cmcurl/lib/netrc.c b/Utilities/cmcurl/lib/netrc.c index 7435d94..06f8ea1 100644 --- a/Utilities/cmcurl/lib/netrc.c +++ b/Utilities/cmcurl/lib/netrc.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -31,13 +31,11 @@ #include "strequal.h" #include "strtok.h" -#include "curl_memory.h" #include "rawstr.h" +#include "curl_printf.h" -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - -/* The last #include file should be: */ +/* The last #include files should be: */ +#include "curl_memory.h" #include "memdebug.h" /* Get user and password from .netrc when given a machine name */ @@ -104,16 +102,16 @@ int Curl_parsenetrc(const char *host, netrcfile = curl_maprintf("%s%s%s", home, DIR_CHAR, NETRC); if(home_alloc) - Curl_safefree(home); + free(home); if(!netrcfile) { return -1; } netrc_alloc = TRUE; } - file = fopen(netrcfile, "r"); + file = fopen(netrcfile, FOPEN_READTEXT); if(netrc_alloc) - Curl_safefree(netrcfile); + free(netrcfile); if(file) { char *tok; char *tok_buf; @@ -139,6 +137,10 @@ int Curl_parsenetrc(const char *host, 'password'. */ state=HOSTFOUND; } + else if(Curl_raw_equal("default", tok)) { + state=HOSTVALID; + retcode=0; /* we did find our host */ + } break; case HOSTFOUND: if(Curl_raw_equal(host, tok)) { diff --git a/Utilities/cmcurl/lib/non-ascii.c b/Utilities/cmcurl/lib/non-ascii.c index 91d6a54..6ccb449 100644 --- a/Utilities/cmcurl/lib/non-ascii.c +++ b/Utilities/cmcurl/lib/non-ascii.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -82,17 +82,16 @@ CURLcode Curl_convert_clone(struct SessionHandle *data, CURLcode Curl_convert_to_network(struct SessionHandle *data, char *buffer, size_t length) { - CURLcode rc; - if(data->set.convtonetwork) { /* use translation callback */ - rc = data->set.convtonetwork(buffer, length); - if(rc != CURLE_OK) { + CURLcode result = data->set.convtonetwork(buffer, length); + if(result) { failf(data, "CURLOPT_CONV_TO_NETWORK_FUNCTION callback returned %d: %s", - (int)rc, curl_easy_strerror(rc)); + (int)result, curl_easy_strerror(result)); } - return rc; + + return result; } else { #ifdef HAVE_ICONV @@ -143,17 +142,16 @@ CURLcode Curl_convert_to_network(struct SessionHandle *data, CURLcode Curl_convert_from_network(struct SessionHandle *data, char *buffer, size_t length) { - CURLcode rc; - if(data->set.convfromnetwork) { /* use translation callback */ - rc = data->set.convfromnetwork(buffer, length); - if(rc != CURLE_OK) { + CURLcode result = data->set.convfromnetwork(buffer, length); + if(result) { failf(data, "CURLOPT_CONV_FROM_NETWORK_FUNCTION callback returned %d: %s", - (int)rc, curl_easy_strerror(rc)); + (int)result, curl_easy_strerror(result)); } - return rc; + + return result; } else { #ifdef HAVE_ICONV @@ -204,17 +202,16 @@ CURLcode Curl_convert_from_network(struct SessionHandle *data, CURLcode Curl_convert_from_utf8(struct SessionHandle *data, char *buffer, size_t length) { - CURLcode rc; - if(data->set.convfromutf8) { /* use translation callback */ - rc = data->set.convfromutf8(buffer, length); - if(rc != CURLE_OK) { + CURLcode result = data->set.convfromutf8(buffer, length); + if(result) { failf(data, "CURLOPT_CONV_FROM_UTF8_FUNCTION callback returned %d: %s", - (int)rc, curl_easy_strerror(rc)); + (int)result, curl_easy_strerror(result)); } - return rc; + + return result; } else { #ifdef HAVE_ICONV @@ -319,24 +316,22 @@ void Curl_convert_close(struct SessionHandle *data) */ CURLcode Curl_convert_form(struct SessionHandle *data, struct FormData *form) { - struct FormData *next; - CURLcode rc; - - if(!form) - return CURLE_OK; + CURLcode result; if(!data) return CURLE_BAD_FUNCTION_ARGUMENT; - do { - next=form->next; /* the following form line */ + while(form) { if(form->type == FORM_DATA) { - rc = Curl_convert_to_network(data, form->line, form->length); + result = Curl_convert_to_network(data, form->line, form->length); /* Curl_convert_to_network calls failf if unsuccessful */ - if(rc != CURLE_OK) - return rc; + if(result) + return result; } - } while((form = next) != NULL); /* continue */ + + form = form->next; + } + return CURLE_OK; } diff --git a/Utilities/cmcurl/lib/nwlib.c b/Utilities/cmcurl/lib/nwlib.c index 252bf11..bd3f27e 100644 --- a/Utilities/cmcurl/lib/nwlib.c +++ b/Utilities/cmcurl/lib/nwlib.c @@ -282,9 +282,7 @@ int DisposeLibraryData( void *data ) if(data) { void *tenbytes = ((libdata_t *) data)->tenbytes; - if(tenbytes) - free(tenbytes); - + free(tenbytes); free(data); } @@ -296,9 +294,7 @@ void DisposeThreadData( void *data ) if(data) { void *twentybytes = ((libthreaddata_t *) data)->twentybytes; - if(twentybytes) - free(twentybytes); - + free(twentybytes); free(data); } } diff --git a/Utilities/cmcurl/lib/openldap.c b/Utilities/cmcurl/lib/openldap.c index df8d938..bee552f 100644 --- a/Utilities/cmcurl/lib/openldap.c +++ b/Utilities/cmcurl/lib/openldap.c @@ -5,8 +5,8 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2010, 2013, Howard Chu, <hyc@openldap.org> - * Copyright (C) 2011 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2010, Howard Chu, <hyc@openldap.org> + * Copyright (C) 2011 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -44,13 +44,12 @@ #include "vtls/vtls.h" #include "transfer.h" #include "curl_ldap.h" -#include "curl_memory.h" #include "curl_base64.h" #include "connect.h" +#include "curl_printf.h" -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - +/* The last #include files should be: */ +#include "curl_memory.h" #include "memdebug.h" #ifndef _LDAP_PVT_H @@ -59,7 +58,7 @@ extern int ldap_init_fd(ber_socket_t fd, int proto, const char *url, LDAP **ld); #endif -static CURLcode ldap_setup(struct connectdata *conn); +static CURLcode ldap_setup_connection(struct connectdata *conn); static CURLcode ldap_do(struct connectdata *conn, bool *done); static CURLcode ldap_done(struct connectdata *conn, CURLcode, bool); static CURLcode ldap_connect(struct connectdata *conn, bool *done); @@ -74,7 +73,7 @@ static Curl_recv ldap_recv; const struct Curl_handler Curl_handler_ldap = { "LDAP", /* scheme */ - ldap_setup, /* setup_connection */ + ldap_setup_connection, /* setup_connection */ ldap_do, /* do_it */ ldap_done, /* done */ ZERO_NULL, /* do_more */ @@ -99,7 +98,7 @@ const struct Curl_handler Curl_handler_ldap = { const struct Curl_handler Curl_handler_ldaps = { "LDAPS", /* scheme */ - ldap_setup, /* setup_connection */ + ldap_setup_connection, /* setup_connection */ ldap_do, /* do_it */ ldap_done, /* done */ ZERO_NULL, /* do_more */ @@ -148,7 +147,7 @@ typedef struct ldapreqinfo { int nument; } ldapreqinfo; -static CURLcode ldap_setup(struct connectdata *conn) +static CURLcode ldap_setup_connection(struct connectdata *conn) { ldapconninfo *li; LDAPURLDesc *lud; @@ -190,9 +189,11 @@ static Sockbuf_IO ldapsb_tls; static CURLcode ldap_connect(struct connectdata *conn, bool *done) { ldapconninfo *li = conn->proto.generic; - struct SessionHandle *data=conn->data; + struct SessionHandle *data = conn->data; int rc, proto = LDAP_VERSION3; - char hosturl[1024], *ptr; + char hosturl[1024]; + char *ptr; + (void)done; strcpy(hosturl, "ldap"); @@ -213,10 +214,10 @@ static CURLcode ldap_connect(struct connectdata *conn, bool *done) #ifdef USE_SSL if(conn->handler->flags & PROTOPT_SSL) { - CURLcode res; - res = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &li->ssldone); - if(res) - return res; + CURLcode result; + result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &li->ssldone); + if(result) + return result; } #endif @@ -226,9 +227,9 @@ static CURLcode ldap_connect(struct connectdata *conn, bool *done) static CURLcode ldap_connecting(struct connectdata *conn, bool *done) { ldapconninfo *li = conn->proto.generic; - struct SessionHandle *data=conn->data; - LDAPMessage *result = NULL; - struct timeval tv = {0,1}, *tvp; + struct SessionHandle *data = conn->data; + LDAPMessage *msg = NULL; + struct timeval tv = {0, 1}, *tvp; int rc, err; char *info = NULL; @@ -236,11 +237,12 @@ static CURLcode ldap_connecting(struct connectdata *conn, bool *done) if(conn->handler->flags & PROTOPT_SSL) { /* Is the SSL handshake complete yet? */ if(!li->ssldone) { - CURLcode res = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, - &li->ssldone); - if(res || !li->ssldone) - return res; + CURLcode result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, + &li->ssldone); + if(result || !li->ssldone) + return result; } + /* Have we installed the libcurl SSL handlers into the sockbuf yet? */ if(!li->sslinst) { Sockbuf *sb; @@ -279,7 +281,7 @@ retry: return CURLE_OK; } - rc = ldap_result(li->ld, li->msgid, LDAP_MSG_ONE, tvp, &result); + rc = ldap_result(li->ld, li->msgid, LDAP_MSG_ONE, tvp, &msg); if(rc < 0) { failf(data, "LDAP local: bind ldap_result %s", ldap_err2string(rc)); return CURLE_LDAP_CANNOT_BIND; @@ -288,11 +290,13 @@ retry: /* timed out */ return CURLE_OK; } - rc = ldap_parse_result(li->ld, result, &err, NULL, &info, NULL, NULL, 1); + + rc = ldap_parse_result(li->ld, msg, &err, NULL, &info, NULL, NULL, 1); if(rc) { failf(data, "LDAP local: bind ldap_parse_result %s", ldap_err2string(rc)); return CURLE_LDAP_CANNOT_BIND; } + /* Try to fallback to LDAPv2? */ if(err == LDAP_PROTOCOL_ERROR) { int proto; @@ -321,6 +325,7 @@ retry: ldap_memfree(info); conn->recv[FIRSTSOCKET] = ldap_recv; *done = TRUE; + return CURLE_OK; } @@ -375,7 +380,7 @@ static CURLcode ldap_do(struct connectdata *conn, bool *done) failf(data, "LDAP local: ldap_search_ext %s", ldap_err2string(rc)); return CURLE_LDAP_SEARCH_FAILED; } - lr = calloc(1,sizeof(ldapreqinfo)); + lr = calloc(1, sizeof(ldapreqinfo)); if(!lr) return CURLE_OUT_OF_MEMORY; lr->msgid = msgid; @@ -389,6 +394,7 @@ static CURLcode ldap_done(struct connectdata *conn, CURLcode res, bool premature) { ldapreqinfo *lr = conn->data->req.protop; + (void)res; (void)premature; @@ -402,6 +408,7 @@ static CURLcode ldap_done(struct connectdata *conn, CURLcode res, conn->data->req.protop = NULL; free(lr); } + return CURLE_OK; } @@ -409,18 +416,19 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf, size_t len, CURLcode *err) { ldapconninfo *li = conn->proto.generic; - struct SessionHandle *data=conn->data; + struct SessionHandle *data = conn->data; ldapreqinfo *lr = data->req.protop; int rc, ret; - LDAPMessage *result = NULL; + LDAPMessage *msg = NULL; LDAPMessage *ent; BerElement *ber = NULL; - struct timeval tv = {0,1}; + struct timeval tv = {0, 1}; + (void)len; (void)buf; (void)sockindex; - rc = ldap_result(li->ld, lr->msgid, LDAP_MSG_RECEIVED, &tv, &result); + rc = ldap_result(li->ld, lr->msgid, LDAP_MSG_RECEIVED, &tv, &msg); if(rc < 0) { failf(data, "LDAP local: search ldap_result %s", ldap_err2string(rc)); *err = CURLE_RECV_ERROR; @@ -431,10 +439,10 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf, ret = -1; /* timed out */ - if(result == NULL) + if(!msg) return ret; - for(ent = ldap_first_message(li->ld, result); ent; + for(ent = ldap_first_message(li->ld, msg); ent; ent = ldap_next_message(li->ld, ent)) { struct berval bv, *bvals, **bvp = &bvals; int binary = 0, msgtype; @@ -477,9 +485,18 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf, *err = CURLE_RECV_ERROR; return -1; } - Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"DN: ", 4); - Curl_client_write(conn, CLIENTWRITE_BODY, (char *)bv.bv_val, bv.bv_len); - Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1); + *err = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"DN: ", 4); + if(*err) + return -1; + + *err = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)bv.bv_val, + bv.bv_len); + if(*err) + return -1; + + *err = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1); + if(*err) + return -1; data->req.bytecount += bv.bv_len + 5; for(rc = ldap_get_attribute_ber(li->ld, ent, ber, &bv, bvp); @@ -496,10 +513,18 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf, for(i=0; bvals[i].bv_val != NULL; i++) { int binval = 0; - Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\t", 1); - Curl_client_write(conn, CLIENTWRITE_BODY, (char *)bv.bv_val, - bv.bv_len); - Curl_client_write(conn, CLIENTWRITE_BODY, (char *)":", 1); + *err = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\t", 1); + if(*err) + return -1; + + *err = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)bv.bv_val, + bv.bv_len); + if(*err) + return -1; + + *err = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)":", 1); + if(*err) + return -1; data->req.bytecount += bv.bv_len + 2; if(!binary) { @@ -529,36 +554,55 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf, if(error) { ber_memfree(bvals); ber_free(ber, 0); - ldap_msgfree(result); + ldap_msgfree(msg); *err = error; return -1; } - Curl_client_write(conn, CLIENTWRITE_BODY, (char *)": ", 2); + *err = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)": ", 2); + if(*err) + return -1; + data->req.bytecount += 2; if(val_b64_sz > 0) { - Curl_client_write(conn, CLIENTWRITE_BODY, val_b64, val_b64_sz); + *err = Curl_client_write(conn, CLIENTWRITE_BODY, val_b64, + val_b64_sz); + if(*err) + return -1; free(val_b64); data->req.bytecount += val_b64_sz; } } else { - Curl_client_write(conn, CLIENTWRITE_BODY, (char *)" ", 1); - Curl_client_write(conn, CLIENTWRITE_BODY, bvals[i].bv_val, - bvals[i].bv_len); + *err = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)" ", 1); + if(*err) + return -1; + + *err = Curl_client_write(conn, CLIENTWRITE_BODY, bvals[i].bv_val, + bvals[i].bv_len); + if(*err) + return -1; + data->req.bytecount += bvals[i].bv_len + 1; } - Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0); + *err = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0); + if(*err) + return -1; + data->req.bytecount++; } ber_memfree(bvals); - Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0); + *err = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0); + if(*err) + return -1; data->req.bytecount++; } - Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0); + *err = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0); + if(*err) + return -1; data->req.bytecount++; ber_free(ber, 0); } - ldap_msgfree(result); + ldap_msgfree(msg); return ret; } diff --git a/Utilities/cmcurl/lib/parsedate.c b/Utilities/cmcurl/lib/parsedate.c index ecb8dfb..3e168f5 100644 --- a/Utilities/cmcurl/lib/parsedate.c +++ b/Utilities/cmcurl/lib/parsedate.c @@ -545,7 +545,7 @@ static int parsedate(const char *date, time_t *output) time_t curl_getdate(const char *p, const time_t *now) { - time_t parsed; + time_t parsed = -1; int rc = parsedate(p, &parsed); (void)now; /* legacy argument from the past that we ignore */ diff --git a/Utilities/cmcurl/lib/pingpong.c b/Utilities/cmcurl/lib/pingpong.c index c7e89d0..1670792 100644 --- a/Utilities/cmcurl/lib/pingpong.c +++ b/Utilities/cmcurl/lib/pingpong.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -34,9 +34,7 @@ #include "multiif.h" #include "non-ascii.h" #include "vtls/vtls.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> +#include "curl_printf.h" #include "curl_memory.h" /* The last #include file should be: */ @@ -165,7 +163,7 @@ CURLcode Curl_pp_vsendf(struct pingpong *pp, size_t write_len; char *fmt_crlf; char *s; - CURLcode error; + CURLcode result; struct connectdata *conn = pp->conn; struct SessionHandle *data = conn->data; @@ -191,26 +189,26 @@ CURLcode Curl_pp_vsendf(struct pingpong *pp, Curl_pp_init(pp); - error = Curl_convert_to_network(data, s, write_len); + result = Curl_convert_to_network(data, s, write_len); /* Curl_convert_to_network calls failf if unsuccessful */ - if(error) { + if(result) { free(s); - return error; + return result; } #ifdef HAVE_GSSAPI conn->data_prot = PROT_CMD; #endif - error = Curl_write(conn, conn->sock[FIRSTSOCKET], s, write_len, + result = Curl_write(conn, conn->sock[FIRSTSOCKET], s, write_len, &bytes_written); #ifdef HAVE_GSSAPI DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST); conn->data_prot = data_sec; #endif - if(error) { + if(result) { free(s); - return error; + return result; } if(conn->data->set.verbose) @@ -247,15 +245,15 @@ CURLcode Curl_pp_vsendf(struct pingpong *pp, CURLcode Curl_pp_sendf(struct pingpong *pp, const char *fmt, ...) { - CURLcode res; + CURLcode result; va_list ap; va_start(ap, fmt); - res = Curl_pp_vsendf(pp, fmt, ap); + result = Curl_pp_vsendf(pp, fmt, ap); va_end(ap); - return res; + return result; } /* @@ -285,8 +283,6 @@ CURLcode Curl_pp_readresp(curl_socket_t sockfd, /* number of bytes in the current line, so far */ perline = (ssize_t)(ptr-pp->linestart_resp); - keepon=TRUE; - while((pp->nread_resp<BUFSIZE) && (keepon && !result)) { if(pp->cache) { @@ -305,30 +301,28 @@ CURLcode Curl_pp_readresp(curl_socket_t sockfd, pp->cache_size = 0; /* zero the size just in case */ } else { - int res; #ifdef HAVE_GSSAPI enum protection_level prot = conn->data_prot; conn->data_prot = PROT_CLEAR; #endif DEBUGASSERT((ptr+BUFSIZE-pp->nread_resp) <= (buf+BUFSIZE+1)); - res = Curl_read(conn, sockfd, ptr, BUFSIZE-pp->nread_resp, - &gotbytes); + result = Curl_read(conn, sockfd, ptr, BUFSIZE-pp->nread_resp, + &gotbytes); #ifdef HAVE_GSSAPI DEBUGASSERT(prot > PROT_NONE && prot < PROT_LAST); conn->data_prot = prot; #endif - if(res == CURLE_AGAIN) + if(result == CURLE_AGAIN) return CURLE_OK; /* return */ - if((res == CURLE_OK) && (gotbytes > 0)) + if(!result && (gotbytes > 0)) /* convert from the network encoding */ - res = Curl_convert_from_network(data, ptr, gotbytes); + result = Curl_convert_from_network(data, ptr, gotbytes); /* Curl_convert_from_network calls failf if unsuccessful */ - if(CURLE_OK != res) { - result = (CURLcode)res; /* Set outer result variable to this error. */ + if(result) + /* Set outer result variable to this error. */ keepon = FALSE; - } } if(!keepon) @@ -478,11 +472,9 @@ CURLcode Curl_pp_flushsend(struct pingpong *pp) /* we have a piece of a command still left to send */ struct connectdata *conn = pp->conn; ssize_t written; - CURLcode result = CURLE_OK; curl_socket_t sock = conn->sock[FIRSTSOCKET]; - - result = Curl_write(conn, sock, pp->sendthis + pp->sendsize - - pp->sendleft, pp->sendleft, &written); + CURLcode result = Curl_write(conn, sock, pp->sendthis + pp->sendsize - + pp->sendleft, pp->sendleft, &written); if(result) return result; @@ -501,10 +493,8 @@ CURLcode Curl_pp_flushsend(struct pingpong *pp) CURLcode Curl_pp_disconnect(struct pingpong *pp) { - if(pp->cache) { - free(pp->cache); - pp->cache = NULL; - } + free(pp->cache); + pp->cache = NULL; return CURLE_OK; } diff --git a/Utilities/cmcurl/lib/pipeline.c b/Utilities/cmcurl/lib/pipeline.c index 8d2544b..1b38836 100644 --- a/Utilities/cmcurl/lib/pipeline.c +++ b/Utilities/cmcurl/lib/pipeline.c @@ -6,7 +6,7 @@ * \___|\___/|_| \_\_____| * * Copyright (C) 2013, Linus Nielsen Feltzing, <linus@haxx.se> - * Copyright (C) 2013-2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2013-2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -32,7 +32,6 @@ #include "pipeline.h" #include "sendf.h" #include "rawstr.h" -#include "bundles.h" #include "curl_memory.h" /* The last #include file should be: */ @@ -49,15 +48,13 @@ static void site_blacklist_llist_dtor(void *user, void *element) (void)user; Curl_safefree(entry->hostname); - Curl_safefree(entry); + free(entry); } static void server_blacklist_llist_dtor(void *user, void *element) { - char *server_name = element; (void)user; - - Curl_safefree(server_name); + free(element); } bool Curl_pipeline_penalized(struct SessionHandle *data, @@ -94,20 +91,29 @@ bool Curl_pipeline_penalized(struct SessionHandle *data, return FALSE; } +static CURLcode addHandleToPipeline(struct SessionHandle *data, + struct curl_llist *pipeline) +{ + if(!Curl_llist_insert_next(pipeline, pipeline->tail, data)) + return CURLE_OUT_OF_MEMORY; + return CURLE_OK; +} + + CURLcode Curl_add_handle_to_pipeline(struct SessionHandle *handle, struct connectdata *conn) { struct curl_llist_element *sendhead = conn->send_pipe->head; struct curl_llist *pipeline; - CURLcode rc; + CURLcode result; pipeline = conn->send_pipe; - rc = Curl_addHandleToPipeline(handle, pipeline); + result = addHandleToPipeline(handle, pipeline); if(pipeline == conn->send_pipe && sendhead != conn->send_pipe->head) { /* this is a new one as head, expire it */ - conn->writechannel_inuse = FALSE; /* not in use yet */ + Curl_pipeline_leave_write(conn); /* not in use yet */ Curl_expire(conn->send_pipe->head->ptr, 1); } @@ -115,7 +121,7 @@ CURLcode Curl_add_handle_to_pipeline(struct SessionHandle *handle, print_pipeline(conn); #endif - return rc; + return result; } /* Move this transfer from the sending list to the receiving list. @@ -138,7 +144,7 @@ void Curl_move_handle_from_send_to_recv_pipe(struct SessionHandle *handle, if(conn->send_pipe->head) { /* Since there's a new easy handle at the start of the send pipeline, set its timeout value to 1ms to make it trigger instantly */ - conn->writechannel_inuse = FALSE; /* not used now */ + Curl_pipeline_leave_write(conn); /* not used now */ #ifdef DEBUGBUILD infof(conn->data, "%p is at send pipe head B!\n", (void *)conn->send_pipe->head->ptr); @@ -251,7 +257,7 @@ CURLMcode Curl_pipeline_set_site_blacklist(char **sites, bool Curl_pipeline_server_blacklisted(struct SessionHandle *handle, char *server_name) { - if(handle->multi) { + if(handle->multi && server_name) { struct curl_llist *blacklist = Curl_multi_pipelining_server_bl(handle->multi); @@ -272,7 +278,7 @@ bool Curl_pipeline_server_blacklisted(struct SessionHandle *handle, } } - infof(handle, "Server %s is not blacklisted\n", server_name); + DEBUGF(infof(handle, "Server %s is not blacklisted\n", server_name)); } return FALSE; } @@ -314,6 +320,93 @@ CURLMcode Curl_pipeline_set_server_blacklist(char **servers, return CURLM_OK; } +static bool pipe_head(struct SessionHandle *data, + struct curl_llist *pipeline) +{ + struct curl_llist_element *curr = pipeline->head; + if(curr) + return (curr->ptr == data) ? TRUE : FALSE; + + return FALSE; +} + +/* returns TRUE if the given handle is head of the recv pipe */ +bool Curl_recvpipe_head(struct SessionHandle *data, + struct connectdata *conn) +{ + return pipe_head(data, conn->recv_pipe); +} + +/* returns TRUE if the given handle is head of the send pipe */ +bool Curl_sendpipe_head(struct SessionHandle *data, + struct connectdata *conn) +{ + return pipe_head(data, conn->send_pipe); +} + + +/* + * Check if the write channel is available and this handle as at the head, + * then grab the channel and return TRUE. + * + * If not available, return FALSE. + */ + +bool Curl_pipeline_checkget_write(struct SessionHandle *data, + struct connectdata *conn) +{ + if(conn->bits.multiplex) + /* when multiplexing, we can use it at once */ + return TRUE; + + if(!conn->writechannel_inuse && Curl_sendpipe_head(data, conn)) { + /* Grab the channel */ + conn->writechannel_inuse = TRUE; + return TRUE; + } + return FALSE; +} + + +/* + * Check if the read channel is available and this handle as at the head, then + * grab the channel and return TRUE. + * + * If not available, return FALSE. + */ + +bool Curl_pipeline_checkget_read(struct SessionHandle *data, + struct connectdata *conn) +{ + if(conn->bits.multiplex) + /* when multiplexing, we can use it at once */ + return TRUE; + + if(!conn->readchannel_inuse && Curl_recvpipe_head(data, conn)) { + /* Grab the channel */ + conn->readchannel_inuse = TRUE; + return TRUE; + } + return FALSE; +} + +/* + * The current user of the pipeline write channel gives it up. + */ +void Curl_pipeline_leave_write(struct connectdata *conn) +{ + conn->writechannel_inuse = FALSE; +} + +/* + * The current user of the pipeline read channel gives it up. + */ +void Curl_pipeline_leave_read(struct connectdata *conn) +{ + conn->readchannel_inuse = FALSE; +} + + #if 0 void print_pipeline(struct connectdata *conn) { diff --git a/Utilities/cmcurl/lib/pipeline.h b/Utilities/cmcurl/lib/pipeline.h index 96c4c33..bf229f1 100644 --- a/Utilities/cmcurl/lib/pipeline.h +++ b/Utilities/cmcurl/lib/pipeline.h @@ -7,6 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * + * Copyright (C) 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * Copyright (C) 2013 - 2014, Linus Nielsen Feltzing, <linus@haxx.se> * * This software is licensed as described in the file COPYING, which @@ -41,4 +42,15 @@ bool Curl_pipeline_server_blacklisted(struct SessionHandle *handle, CURLMcode Curl_pipeline_set_server_blacklist(char **servers, struct curl_llist **list_ptr); +bool Curl_pipeline_checkget_write(struct SessionHandle *data, + struct connectdata *conn); +bool Curl_pipeline_checkget_read(struct SessionHandle *data, + struct connectdata *conn); +void Curl_pipeline_leave_write(struct connectdata *conn); +void Curl_pipeline_leave_read(struct connectdata *conn); +bool Curl_recvpipe_head(struct SessionHandle *data, + struct connectdata *conn); +bool Curl_sendpipe_head(struct SessionHandle *data, + struct connectdata *conn); + #endif /* HEADER_CURL_PIPELINE_H */ diff --git a/Utilities/cmcurl/lib/pop3.c b/Utilities/cmcurl/lib/pop3.c index dc64f81..53510a2 100644 --- a/Utilities/cmcurl/lib/pop3.c +++ b/Utilities/cmcurl/lib/pop3.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -63,7 +63,6 @@ #include <curl/curl.h> #include "urldata.h" #include "sendf.h" -#include "if2ip.h" #include "hostip.h" #include "progress.h" #include "transfer.h" @@ -84,10 +83,7 @@ #include "curl_sasl.h" #include "curl_md5.h" #include "warnless.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - +#include "curl_printf.h" #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" @@ -107,10 +103,10 @@ static CURLcode pop3_setup_connection(struct connectdata *conn); static CURLcode pop3_parse_url_options(struct connectdata *conn); static CURLcode pop3_parse_url_path(struct connectdata *conn); static CURLcode pop3_parse_custom_request(struct connectdata *conn); -static CURLcode pop3_calc_sasl_details(struct connectdata *conn, - const char **mech, - char **initresp, size_t *len, - pop3state *state1, pop3state *state2); +static CURLcode pop3_perform_auth(struct connectdata *conn, const char *mech, + const char *initresp); +static CURLcode pop3_continue_auth(struct connectdata *conn, const char *resp); +static void pop3_get_message(char *buffer, char** outptr); /* * POP3 protocol handler. @@ -215,6 +211,17 @@ static const struct Curl_handler Curl_handler_pop3s_proxy = { #endif #endif +/* SASL parameters for the pop3 protocol */ +static const struct SASLproto saslpop3 = { + "pop", /* The service name */ + '+', /* Code received when continuation is expected */ + '+', /* Code to receive upon authentication success */ + 255 - 8, /* Maximum initial response length (no max) */ + pop3_perform_auth, /* Send authentication command */ + pop3_continue_auth, /* Send authentication continuation */ + pop3_get_message /* Get SASL response message */ +}; + #ifdef USE_SSL static void pop3_to_pop3s(struct connectdata *conn) { @@ -313,20 +320,7 @@ static void state(struct connectdata *conn, pop3state newstate) "CAPA", "STARTTLS", "UPGRADETLS", - "AUTH_PLAIN", - "AUTH_LOGIN", - "AUTH_LOGIN_PASSWD", - "AUTH_CRAMMD5", - "AUTH_DIGESTMD5", - "AUTH_DIGESTMD5_RESP", - "AUTH_NTLM", - "AUTH_NTLM_TYPE2MSG", - "AUTH_GSSAPI", - "AUTH_GSSAPI_TOKEN", - "AUTH_GSSAPI_NO_DATA", - "AUTH_XOAUTH2", - "AUTH_CANCEL", - "AUTH_FINAL", + "AUTH", "APOP", "USER", "PASS", @@ -355,9 +349,9 @@ static CURLcode pop3_perform_capa(struct connectdata *conn) CURLcode result = CURLE_OK; struct pop3_conn *pop3c = &conn->proto.pop3c; - pop3c->authmechs = 0; /* No known authentication mechanisms yet */ - pop3c->authused = 0; /* Clear the authentication mechanism used */ - pop3c->tls_supported = FALSE; /* Clear the TLS capability */ + pop3c->sasl.authmechs = SASL_AUTH_NONE; /* No known auth. mechanisms yet */ + pop3c->sasl.authused = SASL_AUTH_NONE; /* Clear the auth. mechanism used */ + pop3c->tls_supported = FALSE; /* Clear the TLS capability */ /* Send the CAPA command */ result = Curl_pp_sendf(&pop3c->pp, "%s", "CAPA"); @@ -501,25 +495,18 @@ static CURLcode pop3_perform_apop(struct connectdata *conn) */ static CURLcode pop3_perform_auth(struct connectdata *conn, const char *mech, - const char *initresp, size_t len, - pop3state state1, pop3state state2) + const char *initresp) { CURLcode result = CURLE_OK; struct pop3_conn *pop3c = &conn->proto.pop3c; - if(initresp && 8 + strlen(mech) + len <= 255) { /* AUTH <mech> ...<crlf> */ + if(initresp) { /* AUTH <mech> ...<crlf> */ /* Send the AUTH command with the initial response */ result = Curl_pp_sendf(&pop3c->pp, "AUTH %s %s", mech, initresp); - - if(!result) - state(conn, state2); } else { /* Send the AUTH command */ result = Curl_pp_sendf(&pop3c->pp, "AUTH %s", mech); - - if(!result) - state(conn, state1); } return result; @@ -527,6 +514,20 @@ static CURLcode pop3_perform_auth(struct connectdata *conn, /*********************************************************************** * + * pop3_continue_auth() + * + * Sends SASL continuation data or cancellation. + */ +static CURLcode pop3_continue_auth(struct connectdata *conn, + const char *resp) +{ + struct pop3_conn *pop3c = &conn->proto.pop3c; + + return Curl_pp_sendf(&pop3c->pp, "%s", resp); +} + +/*********************************************************************** + * * pop3_perform_authentication() * * Initiates the authentication sequence, with the appropriate SASL @@ -537,40 +538,32 @@ static CURLcode pop3_perform_authentication(struct connectdata *conn) { CURLcode result = CURLE_OK; struct pop3_conn *pop3c = &conn->proto.pop3c; - const char *mech = NULL; - char *initresp = NULL; - size_t len = 0; - pop3state state1 = POP3_STOP; - pop3state state2 = POP3_STOP; + saslprogress progress = SASL_IDLE; - /* Check we have a username and password to authenticate with and end the + /* Check we have enough data to authenticate with and end the connect phase if we don't */ - if(!conn->bits.user_passwd) { + if(!Curl_sasl_can_authenticate(&pop3c->sasl, conn)) { state(conn, POP3_STOP); - return result; } - /* Calculate the SASL login details */ - if(pop3c->authtypes & POP3_TYPE_SASL) - result = pop3_calc_sasl_details(conn, &mech, &initresp, &len, &state1, - &state2); + if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_SASL) { + /* Calculate the SASL login details */ + result = Curl_sasl_start(&pop3c->sasl, conn, FALSE, &progress); - if(!result) { - if(mech && (pop3c->preftype & POP3_TYPE_SASL)) { - /* Perform SASL based authentication */ - result = pop3_perform_auth(conn, mech, initresp, len, state1, state2); + if(!result) + if(progress == SASL_INPROGRESS) + state(conn, POP3_AUTH); + } - Curl_safefree(initresp); - } + if(!result && progress == SASL_IDLE) { #ifndef CURL_DISABLE_CRYPTO_AUTH - else if((pop3c->authtypes & POP3_TYPE_APOP) && - (pop3c->preftype & POP3_TYPE_APOP)) + if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_APOP) /* Perform APOP authentication */ result = pop3_perform_apop(conn); + else #endif - else if((pop3c->authtypes & POP3_TYPE_CLEARTEXT) && - (pop3c->preftype & POP3_TYPE_CLEARTEXT)) + if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_CLEARTEXT) /* Perform clear text authentication */ result = pop3_perform_user(conn); else { @@ -727,6 +720,9 @@ static CURLcode pop3_state_capa_resp(struct connectdata *conn, int pop3code, /* Loop through the data line */ for(;;) { + size_t llen; + unsigned int mechbit; + while(len && (*line == ' ' || *line == '\t' || *line == '\r' || *line == '\n')) { @@ -745,22 +741,9 @@ static CURLcode pop3_state_capa_resp(struct connectdata *conn, int pop3code, wordlen++; /* Test the word for a matching authentication mechanism */ - if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_LOGIN)) - pop3c->authmechs |= SASL_MECH_LOGIN; - else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_PLAIN)) - pop3c->authmechs |= SASL_MECH_PLAIN; - else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_CRAM_MD5)) - pop3c->authmechs |= SASL_MECH_CRAM_MD5; - else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_DIGEST_MD5)) - pop3c->authmechs |= SASL_MECH_DIGEST_MD5; - else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_GSSAPI)) - pop3c->authmechs |= SASL_MECH_GSSAPI; - else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_EXTERNAL)) - pop3c->authmechs |= SASL_MECH_EXTERNAL; - else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_NTLM)) - pop3c->authmechs |= SASL_MECH_NTLM; - else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_XOAUTH2)) - pop3c->authmechs |= SASL_MECH_XOAUTH2; + if((mechbit = Curl_sasl_decode_mech(line, wordlen, &llen)) && + llen == wordlen) + pop3c->sasl.authmechs |= mechbit; line += wordlen; len -= wordlen; @@ -818,575 +801,42 @@ static CURLcode pop3_state_starttls_resp(struct connectdata *conn, return result; } -/* For AUTH PLAIN (without initial response) responses */ -static CURLcode pop3_state_auth_plain_resp(struct connectdata *conn, - int pop3code, - pop3state instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - size_t len = 0; - char *plainauth = NULL; - - (void)instate; /* no use for this yet */ - - if(pop3code != '+') { - failf(data, "Access denied. %c", pop3code); - result = CURLE_LOGIN_DENIED; - } - else { - /* Create the authorisation message */ - result = Curl_sasl_create_plain_message(data, conn->user, conn->passwd, - &plainauth, &len); - if(!result && plainauth) { - /* Send the message */ - result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", plainauth); - - if(!result) - state(conn, POP3_AUTH_FINAL); - } - } - - Curl_safefree(plainauth); - - return result; -} - -/* For AUTH LOGIN (without initial response) responses */ -static CURLcode pop3_state_auth_login_resp(struct connectdata *conn, - int pop3code, - pop3state instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - size_t len = 0; - char *authuser = NULL; - - (void)instate; /* no use for this yet */ - - if(pop3code != '+') { - failf(data, "Access denied: %d", pop3code); - result = CURLE_LOGIN_DENIED; - } - else { - /* Create the user message */ - result = Curl_sasl_create_login_message(data, conn->user, - &authuser, &len); - if(!result && authuser) { - /* Send the user */ - result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", authuser); - - if(!result) - state(conn, POP3_AUTH_LOGIN_PASSWD); - } - } - - Curl_safefree(authuser); - - return result; -} - -/* For AUTH LOGIN user entry responses */ -static CURLcode pop3_state_auth_login_password_resp(struct connectdata *conn, - int pop3code, - pop3state instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - size_t len = 0; - char *authpasswd = NULL; - - (void)instate; /* no use for this yet */ - - if(pop3code != '+') { - failf(data, "Access denied: %d", pop3code); - result = CURLE_LOGIN_DENIED; - } - else { - /* Create the password message */ - result = Curl_sasl_create_login_message(data, conn->passwd, - &authpasswd, &len); - if(!result && authpasswd) { - /* Send the password */ - result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", authpasswd); - - if(!result) - state(conn, POP3_AUTH_FINAL); - } - } - - Curl_safefree(authpasswd); - - return result; -} - -#ifndef CURL_DISABLE_CRYPTO_AUTH -/* For AUTH CRAM-MD5 responses */ -static CURLcode pop3_state_auth_cram_resp(struct connectdata *conn, - int pop3code, - pop3state instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - char *chlg = NULL; - char *chlg64 = NULL; - char *rplyb64 = NULL; - size_t len = 0; - - (void)instate; /* no use for this yet */ - - if(pop3code != '+') { - failf(data, "Access denied: %d", pop3code); - return CURLE_LOGIN_DENIED; - } - - /* Get the challenge message */ - pop3_get_message(data->state.buffer, &chlg64); - - /* Decode the challenge message */ - result = Curl_sasl_decode_cram_md5_message(chlg64, &chlg, &len); - if(result) { - /* Send the cancellation */ - result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "*"); - - if(!result) - state(conn, POP3_AUTH_CANCEL); - } - else { - /* Create the response message */ - result = Curl_sasl_create_cram_md5_message(data, chlg, conn->user, - conn->passwd, &rplyb64, &len); - if(!result && rplyb64) { - /* Send the response */ - result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", rplyb64); - - if(!result) - state(conn, POP3_AUTH_FINAL); - } - } - - Curl_safefree(chlg); - Curl_safefree(rplyb64); - - return result; -} - -/* For AUTH DIGEST-MD5 challenge responses */ -static CURLcode pop3_state_auth_digest_resp(struct connectdata *conn, - int pop3code, - pop3state instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - char *chlg64 = NULL; - char *rplyb64 = NULL; - size_t len = 0; - - (void)instate; /* no use for this yet */ - - if(pop3code != '+') { - failf(data, "Access denied: %d", pop3code); - return CURLE_LOGIN_DENIED; - } - - /* Get the challenge message */ - pop3_get_message(data->state.buffer, &chlg64); - - /* Create the response message */ - result = Curl_sasl_create_digest_md5_message(data, chlg64, - conn->user, conn->passwd, - "pop", &rplyb64, &len); - if(result) { - if(result == CURLE_BAD_CONTENT_ENCODING) { - /* Send the cancellation */ - result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "*"); - - if(!result) - state(conn, POP3_AUTH_CANCEL); - } - } - else { - /* Send the response */ - result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", rplyb64); - - if(!result) - state(conn, POP3_AUTH_DIGESTMD5_RESP); - } - - Curl_safefree(rplyb64); - - return result; -} - -/* For AUTH DIGEST-MD5 challenge-response responses */ -static CURLcode pop3_state_auth_digest_resp_resp(struct connectdata *conn, - int pop3code, - pop3state instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - - (void)instate; /* no use for this yet */ - - if(pop3code != '+') { - failf(data, "Authentication failed: %d", pop3code); - result = CURLE_LOGIN_DENIED; - } - else { - /* Send an empty response */ - result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", ""); - - if(!result) - state(conn, POP3_AUTH_FINAL); - } - - return result; -} -#endif - -#ifdef USE_NTLM -/* For AUTH NTLM (without initial response) responses */ -static CURLcode pop3_state_auth_ntlm_resp(struct connectdata *conn, - int pop3code, - pop3state instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - size_t len = 0; - char *type1msg = NULL; - - (void)instate; /* no use for this yet */ - - if(pop3code != '+') { - failf(data, "Access denied: %d", pop3code); - result = CURLE_LOGIN_DENIED; - } - else { - /* Create the type-1 message */ - result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd, - &conn->ntlm, - &type1msg, &len); - if(!result && type1msg) { - /* Send the message */ - result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", type1msg); - - if(!result) - state(conn, POP3_AUTH_NTLM_TYPE2MSG); - } - } - - Curl_safefree(type1msg); - - return result; -} - -/* For NTLM type-2 responses (sent in reponse to our type-1 message) */ -static CURLcode pop3_state_auth_ntlm_type2msg_resp(struct connectdata *conn, - int pop3code, - pop3state instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - char *type2msg = NULL; - char *type3msg = NULL; - size_t len = 0; - - (void)instate; /* no use for this yet */ - - if(pop3code != '+') { - failf(data, "Access denied: %d", pop3code); - result = CURLE_LOGIN_DENIED; - } - else { - /* Get the type-2 message */ - pop3_get_message(data->state.buffer, &type2msg); - - /* Decode the type-2 message */ - result = Curl_sasl_decode_ntlm_type2_message(data, type2msg, &conn->ntlm); - if(result) { - /* Send the cancellation */ - result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "*"); - - if(!result) - state(conn, POP3_AUTH_CANCEL); - } - else { - /* Create the type-3 message */ - result = Curl_sasl_create_ntlm_type3_message(data, conn->user, - conn->passwd, &conn->ntlm, - &type3msg, &len); - if(!result && type3msg) { - /* Send the message */ - result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", type3msg); - - if(!result) - state(conn, POP3_AUTH_FINAL); - } - } - } - - Curl_safefree(type3msg); - - return result; -} -#endif - -#if defined(USE_WINDOWS_SSPI) -/* For AUTH GSSAPI (without initial response) responses */ -static CURLcode pop3_state_auth_gssapi_resp(struct connectdata *conn, - int pop3code, - pop3state instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - struct pop3_conn *pop3c = &conn->proto.pop3c; - size_t len = 0; - char *respmsg = NULL; - - (void)instate; /* no use for this yet */ - - if(pop3code != '+') { - failf(data, "Access denied: %d", pop3code); - result = CURLE_LOGIN_DENIED; - } - else { - /* Create the initial response message */ - result = Curl_sasl_create_gssapi_user_message(data, conn->user, - conn->passwd, "pop", - pop3c->mutual_auth, - NULL, &conn->krb5, - &respmsg, &len); - if(!result && respmsg) { - /* Send the message */ - result = Curl_pp_sendf(&pop3c->pp, "%s", respmsg); - - if(!result) - state(conn, POP3_AUTH_GSSAPI_TOKEN); - } - } - - Curl_safefree(respmsg); - - return result; -} - -/* For AUTH GSSAPI user token responses */ -static CURLcode pop3_state_auth_gssapi_token_resp(struct connectdata *conn, - int pop3code, - pop3state instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - struct pop3_conn *pop3c = &conn->proto.pop3c; - char *chlgmsg = NULL; - char *respmsg = NULL; - size_t len = 0; - - (void)instate; /* no use for this yet */ - - if(pop3code != '+') { - failf(data, "Access denied: %d", pop3code); - result = CURLE_LOGIN_DENIED; - } - else { - /* Get the challenge message */ - pop3_get_message(data->state.buffer, &chlgmsg); - - if(pop3c->mutual_auth) - /* Decode the user token challenge and create the optional response - message */ - result = Curl_sasl_create_gssapi_user_message(data, NULL, NULL, NULL, - pop3c->mutual_auth, - chlgmsg, &conn->krb5, - &respmsg, &len); - else - /* Decode the security challenge and create the response message */ - result = Curl_sasl_create_gssapi_security_message(data, chlgmsg, - &conn->krb5, - &respmsg, &len); - - if(result) { - if(result == CURLE_BAD_CONTENT_ENCODING) { - /* Send the cancellation */ - result = Curl_pp_sendf(&pop3c->pp, "%s", "*"); - - if(!result) - state(conn, POP3_AUTH_CANCEL); - } - } - else { - /* Send the response */ - if(respmsg) - result = Curl_pp_sendf(&pop3c->pp, "%s", respmsg); - else - result = Curl_pp_sendf(&pop3c->pp, "%s", ""); - - if(!result) - state(conn, (pop3c->mutual_auth ? POP3_AUTH_GSSAPI_NO_DATA : - POP3_AUTH_FINAL)); - } - } - - Curl_safefree(respmsg); - - return result; -} - -/* For AUTH GSSAPI no data responses */ -static CURLcode pop3_state_auth_gssapi_no_data_resp(struct connectdata *conn, - int pop3code, - pop3state instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - char *chlgmsg = NULL; - char *respmsg = NULL; - size_t len = 0; - - (void)instate; /* no use for this yet */ - - if(pop3code != '+') { - failf(data, "Access denied: %d", pop3code); - result = CURLE_LOGIN_DENIED; - } - else { - /* Get the challenge message */ - pop3_get_message(data->state.buffer, &chlgmsg); - - /* Decode the security challenge and create the security message */ - result = Curl_sasl_create_gssapi_security_message(data, chlgmsg, - &conn->krb5, - &respmsg, &len); - if(result) { - if(result == CURLE_BAD_CONTENT_ENCODING) { - /* Send the cancellation */ - result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "*"); - - if(!result) - state(conn, POP3_AUTH_CANCEL); - } - } - else { - /* Send the response */ - if(respmsg) { - result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", respmsg); - - if(!result) - state(conn, POP3_AUTH_FINAL); - } - } - } - - Curl_safefree(respmsg); - - return result; -} -#endif - -/* For AUTH XOAUTH2 (without initial response) responses */ -static CURLcode pop3_state_auth_xoauth2_resp(struct connectdata *conn, - int pop3code, pop3state instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - size_t len = 0; - char *xoauth = NULL; - - (void)instate; /* no use for this yet */ - - if(pop3code != '+') { - failf(data, "Access denied: %d", pop3code); - result = CURLE_LOGIN_DENIED; - } - else { - /* Create the authorisation message */ - result = Curl_sasl_create_xoauth2_message(conn->data, conn->user, - conn->xoauth2_bearer, - &xoauth, &len); - if(!result && xoauth) { - /* Send the message */ - result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", xoauth); - - if(!result) - state(conn, POP3_AUTH_FINAL); - } - } - - Curl_safefree(xoauth); - - return result; -} - -/* For AUTH cancellation responses */ -static CURLcode pop3_state_auth_cancel_resp(struct connectdata *conn, - int pop3code, - pop3state instate) +/* For SASL authentication responses */ +static CURLcode pop3_state_auth_resp(struct connectdata *conn, + int pop3code, + pop3state instate) { CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; struct pop3_conn *pop3c = &conn->proto.pop3c; - const char *mech = NULL; - char *initresp = NULL; - size_t len = 0; - pop3state state1 = POP3_STOP; - pop3state state2 = POP3_STOP; + saslprogress progress; - (void)pop3code; (void)instate; /* no use for this yet */ - /* Remove the offending mechanism from the supported list */ - pop3c->authmechs ^= pop3c->authused; - - /* Calculate alternative SASL login details */ - result = pop3_calc_sasl_details(conn, &mech, &initresp, &len, &state1, - &state2); - - if(!result) { - /* Do we have any mechanisms left or can we fallback to another - authentication type? */ - if(mech) { - /* Retry SASL based authentication */ - result = pop3_perform_auth(conn, mech, initresp, len, state1, state2); - - Curl_safefree(initresp); - } + result = Curl_sasl_continue(&pop3c->sasl, conn, pop3code, &progress); + if(!result) + switch(progress) { + case SASL_DONE: + state(conn, POP3_STOP); /* Authenticated */ + break; + case SASL_IDLE: /* No mechanism left after cancellation */ #ifndef CURL_DISABLE_CRYPTO_AUTH - else if((pop3c->authtypes & POP3_TYPE_APOP) && - (pop3c->preftype & POP3_TYPE_APOP)) - /* Perform APOP authentication */ - result = pop3_perform_apop(conn); + if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_APOP) + /* Perform APOP authentication */ + result = pop3_perform_apop(conn); + else #endif - else if((pop3c->authtypes & POP3_TYPE_CLEARTEXT) && - (pop3c->preftype & POP3_TYPE_CLEARTEXT)) - /* Perform clear text authentication */ - result = pop3_perform_user(conn); - else { - failf(data, "Authentication cancelled"); - - result = CURLE_LOGIN_DENIED; + if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_CLEARTEXT) + /* Perform clear text authentication */ + result = pop3_perform_user(conn); + else { + failf(data, "Authentication cancelled"); + result = CURLE_LOGIN_DENIED; + } + break; + default: + break; } - } - - return result; -} - -/* For final responses in the AUTH sequence */ -static CURLcode pop3_state_auth_final_resp(struct connectdata *conn, - int pop3code, - pop3state instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - - (void)instate; /* no use for this yet */ - - if(pop3code != '+') { - failf(data, "Authentication failed: %d", pop3code); - result = CURLE_LOGIN_DENIED; - } - else - /* End of connect phase */ - state(conn, POP3_STOP); return result; } @@ -1553,69 +1003,8 @@ static CURLcode pop3_statemach_act(struct connectdata *conn) result = pop3_state_starttls_resp(conn, pop3code, pop3c->state); break; - case POP3_AUTH_PLAIN: - result = pop3_state_auth_plain_resp(conn, pop3code, pop3c->state); - break; - - case POP3_AUTH_LOGIN: - result = pop3_state_auth_login_resp(conn, pop3code, pop3c->state); - break; - - case POP3_AUTH_LOGIN_PASSWD: - result = pop3_state_auth_login_password_resp(conn, pop3code, - pop3c->state); - break; - -#ifndef CURL_DISABLE_CRYPTO_AUTH - case POP3_AUTH_CRAMMD5: - result = pop3_state_auth_cram_resp(conn, pop3code, pop3c->state); - break; - - case POP3_AUTH_DIGESTMD5: - result = pop3_state_auth_digest_resp(conn, pop3code, pop3c->state); - break; - - case POP3_AUTH_DIGESTMD5_RESP: - result = pop3_state_auth_digest_resp_resp(conn, pop3code, pop3c->state); - break; -#endif - -#ifdef USE_NTLM - case POP3_AUTH_NTLM: - result = pop3_state_auth_ntlm_resp(conn, pop3code, pop3c->state); - break; - - case POP3_AUTH_NTLM_TYPE2MSG: - result = pop3_state_auth_ntlm_type2msg_resp(conn, pop3code, - pop3c->state); - break; -#endif - -#if defined(USE_WINDOWS_SSPI) - case POP3_AUTH_GSSAPI: - result = pop3_state_auth_gssapi_resp(conn, pop3code, pop3c->state); - break; - - case POP3_AUTH_GSSAPI_TOKEN: - result = pop3_state_auth_gssapi_token_resp(conn, pop3code, pop3c->state); - break; - - case POP3_AUTH_GSSAPI_NO_DATA: - result = pop3_state_auth_gssapi_no_data_resp(conn, pop3code, - pop3c->state); - break; -#endif - - case POP3_AUTH_XOAUTH2: - result = pop3_state_auth_xoauth2_resp(conn, pop3code, pop3c->state); - break; - - case POP3_AUTH_CANCEL: - result = pop3_state_auth_cancel_resp(conn, pop3code, pop3c->state); - break; - - case POP3_AUTH_FINAL: - result = pop3_state_auth_final_resp(conn, pop3code, pop3c->state); + case POP3_AUTH: + result = pop3_state_auth_resp(conn, pop3code, pop3c->state); break; #ifndef CURL_DISABLE_CRYPTO_AUTH @@ -1728,7 +1117,7 @@ static CURLcode pop3_connect(struct connectdata *conn, bool *done) /* Set the default preferred authentication type and mechanism */ pop3c->preftype = POP3_TYPE_ANY; - pop3c->prefmech = SASL_AUTH_ANY; + Curl_sasl_init(&pop3c->sasl, &saslpop3); /* Initialise the pingpong layer */ Curl_pp_init(pp); @@ -1880,7 +1269,7 @@ static CURLcode pop3_disconnect(struct connectdata *conn, bool dead_connection) Curl_pp_disconnect(&pop3c->pp); /* Cleanup the SASL module */ - Curl_sasl_cleanup(conn, pop3c->authused); + Curl_sasl_cleanup(conn, pop3c->sasl.authused); /* Cleanup our connection based variables */ Curl_safefree(pop3c->apoptimestamp); @@ -1995,75 +1384,52 @@ static CURLcode pop3_parse_url_options(struct connectdata *conn) { CURLcode result = CURLE_OK; struct pop3_conn *pop3c = &conn->proto.pop3c; - const char *options = conn->options; - const char *ptr = options; - bool reset = TRUE; + const char *ptr = conn->options; + + pop3c->sasl.resetprefs = TRUE; - while(ptr && *ptr) { + while(!result && ptr && *ptr) { const char *key = ptr; + const char *value; while(*ptr && *ptr != '=') ptr++; - if(strnequal(key, "AUTH", 4)) { - size_t len = 0; - const char *value = ++ptr; + value = ptr + 1; - if(reset) { - reset = FALSE; - pop3c->preftype = POP3_TYPE_NONE; - pop3c->prefmech = SASL_AUTH_NONE; - } + while(*ptr && *ptr != ';') + ptr++; - while(*ptr && *ptr != ';') { - ptr++; - len++; - } + if(strnequal(key, "AUTH=", 5)) { + result = Curl_sasl_parse_url_auth_option(&pop3c->sasl, + value, ptr - value); - if(strnequal(value, "*", len)) { - pop3c->preftype = POP3_TYPE_ANY; - pop3c->prefmech = SASL_AUTH_ANY; - } - else if(strnequal(value, "+APOP", len)) { + if(result && strnequal(value, "+APOP", ptr - value)) { pop3c->preftype = POP3_TYPE_APOP; - pop3c->prefmech = SASL_AUTH_NONE; - } - else if(strnequal(value, SASL_MECH_STRING_LOGIN, len)) { - pop3c->preftype = POP3_TYPE_SASL; - pop3c->prefmech |= SASL_MECH_LOGIN; - } - else if(strnequal(value, SASL_MECH_STRING_PLAIN, len)) { - pop3c->preftype = POP3_TYPE_SASL; - pop3c->prefmech |= SASL_MECH_PLAIN; - } - else if(strnequal(value, SASL_MECH_STRING_CRAM_MD5, len)) { - pop3c->preftype = POP3_TYPE_SASL; - pop3c->prefmech |= SASL_MECH_CRAM_MD5; - } - else if(strnequal(value, SASL_MECH_STRING_DIGEST_MD5, len)) { - pop3c->preftype = POP3_TYPE_SASL; - pop3c->prefmech |= SASL_MECH_DIGEST_MD5; - } - else if(strnequal(value, SASL_MECH_STRING_GSSAPI, len)) { - pop3c->preftype = POP3_TYPE_SASL; - pop3c->prefmech |= SASL_MECH_GSSAPI; - } - else if(strnequal(value, SASL_MECH_STRING_NTLM, len)) { - pop3c->preftype = POP3_TYPE_SASL; - pop3c->prefmech |= SASL_MECH_NTLM; - } - else if(strnequal(value, SASL_MECH_STRING_XOAUTH2, len)) { - pop3c->preftype = POP3_TYPE_SASL; - pop3c->prefmech |= SASL_MECH_XOAUTH2; + pop3c->sasl.prefmech = SASL_AUTH_NONE; + result = CURLE_OK; } - - if(*ptr == ';') - ptr++; } else result = CURLE_URL_MALFORMAT; + + if(*ptr == ';') + ptr++; } + if(pop3c->preftype != POP3_TYPE_APOP) + switch(pop3c->sasl.prefmech) { + case SASL_AUTH_NONE: + pop3c->preftype = POP3_TYPE_NONE; + break; + case SASL_AUTH_DEFAULT: + pop3c->preftype = POP3_TYPE_ANY; + break; + default: + pop3c->preftype = POP3_TYPE_SASL; + break; + } + return result; } @@ -2106,110 +1472,6 @@ static CURLcode pop3_parse_custom_request(struct connectdata *conn) /*********************************************************************** * - * pop3_calc_sasl_details() - * - * Calculate the required login details for SASL authentication. - */ -static CURLcode pop3_calc_sasl_details(struct connectdata *conn, - const char **mech, - char **initresp, size_t *len, - pop3state *state1, pop3state *state2) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - struct pop3_conn *pop3c = &conn->proto.pop3c; - - /* Calculate the supported authentication mechanism, by decreasing order of - security, as well as the initial response where appropriate */ -#if defined(USE_WINDOWS_SSPI) - if((pop3c->authmechs & SASL_MECH_GSSAPI) && - (pop3c->prefmech & SASL_MECH_GSSAPI)) { - pop3c->mutual_auth = FALSE; /* TODO: Calculate mutual authentication */ - - *mech = SASL_MECH_STRING_GSSAPI; - *state1 = POP3_AUTH_GSSAPI; - *state2 = POP3_AUTH_GSSAPI_TOKEN; - pop3c->authused = SASL_MECH_GSSAPI; - - if(data->set.sasl_ir) - result = Curl_sasl_create_gssapi_user_message(data, conn->user, - conn->passwd, "pop", - pop3c->mutual_auth, - NULL, &conn->krb5, - initresp, len); - } - else -#endif -#ifndef CURL_DISABLE_CRYPTO_AUTH - if((pop3c->authmechs & SASL_MECH_DIGEST_MD5) && - (pop3c->prefmech & SASL_MECH_DIGEST_MD5)) { - *mech = SASL_MECH_STRING_DIGEST_MD5; - *state1 = POP3_AUTH_DIGESTMD5; - pop3c->authused = SASL_MECH_DIGEST_MD5; - } - else if((pop3c->authmechs & SASL_MECH_CRAM_MD5) && - (pop3c->prefmech & SASL_MECH_CRAM_MD5)) { - *mech = SASL_MECH_STRING_CRAM_MD5; - *state1 = POP3_AUTH_CRAMMD5; - pop3c->authused = SASL_MECH_CRAM_MD5; - } - else -#endif -#ifdef USE_NTLM - if((pop3c->authmechs & SASL_MECH_NTLM) && - (pop3c->prefmech & SASL_MECH_NTLM)) { - *mech = SASL_MECH_STRING_NTLM; - *state1 = POP3_AUTH_NTLM; - *state2 = POP3_AUTH_NTLM_TYPE2MSG; - pop3c->authused = SASL_MECH_NTLM; - - if(data->set.sasl_ir) - result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd, - &conn->ntlm, - initresp, len); - } - else -#endif - if(((pop3c->authmechs & SASL_MECH_XOAUTH2) && - (pop3c->prefmech & SASL_MECH_XOAUTH2) && - (pop3c->prefmech != SASL_AUTH_ANY)) || conn->xoauth2_bearer) { - *mech = SASL_MECH_STRING_XOAUTH2; - *state1 = POP3_AUTH_XOAUTH2; - *state2 = POP3_AUTH_FINAL; - pop3c->authused = SASL_MECH_XOAUTH2; - - if(data->set.sasl_ir) - result = Curl_sasl_create_xoauth2_message(data, conn->user, - conn->xoauth2_bearer, - initresp, len); - } - else if((pop3c->authmechs & SASL_MECH_LOGIN) && - (pop3c->prefmech & SASL_MECH_LOGIN)) { - *mech = SASL_MECH_STRING_LOGIN; - *state1 = POP3_AUTH_LOGIN; - *state2 = POP3_AUTH_LOGIN_PASSWD; - pop3c->authused = SASL_MECH_LOGIN; - - if(data->set.sasl_ir) - result = Curl_sasl_create_login_message(data, conn->user, initresp, len); - } - else if((pop3c->authmechs & SASL_MECH_PLAIN) && - (pop3c->prefmech & SASL_MECH_PLAIN)) { - *mech = SASL_MECH_STRING_PLAIN; - *state1 = POP3_AUTH_PLAIN; - *state2 = POP3_AUTH_FINAL; - pop3c->authused = SASL_MECH_PLAIN; - - if(data->set.sasl_ir) - result = Curl_sasl_create_plain_message(data, conn->user, conn->passwd, - initresp, len); - } - - return result; -} - -/*********************************************************************** - * * Curl_pop3_write() * * This function scans the body after the end-of-body and writes everything diff --git a/Utilities/cmcurl/lib/pop3.h b/Utilities/cmcurl/lib/pop3.h index 729a55a..7bc53aa 100644 --- a/Utilities/cmcurl/lib/pop3.h +++ b/Utilities/cmcurl/lib/pop3.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2009 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2009 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -23,6 +23,7 @@ ***************************************************************************/ #include "pingpong.h" +#include "curl_sasl.h" /**************************************************************************** * POP3 unique setup @@ -35,20 +36,7 @@ typedef enum { POP3_STARTTLS, POP3_UPGRADETLS, /* asynchronously upgrade the connection to SSL/TLS (multi mode only) */ - POP3_AUTH_PLAIN, - POP3_AUTH_LOGIN, - POP3_AUTH_LOGIN_PASSWD, - POP3_AUTH_CRAMMD5, - POP3_AUTH_DIGESTMD5, - POP3_AUTH_DIGESTMD5_RESP, - POP3_AUTH_NTLM, - POP3_AUTH_NTLM_TYPE2MSG, - POP3_AUTH_GSSAPI, - POP3_AUTH_GSSAPI_TOKEN, - POP3_AUTH_GSSAPI_NO_DATA, - POP3_AUTH_XOAUTH2, - POP3_AUTH_CANCEL, - POP3_AUTH_FINAL, + POP3_AUTH, POP3_APOP, POP3_USER, POP3_PASS, @@ -77,14 +65,11 @@ struct pop3_conn { have been received so far */ size_t strip; /* Number of bytes from the start to ignore as non-body */ + struct SASL sasl; /* SASL-related storage */ unsigned int authtypes; /* Accepted authentication types */ - unsigned int authmechs; /* Accepted SASL authentication mechanisms */ unsigned int preftype; /* Preferred authentication type */ - unsigned int prefmech; /* Preferred SASL authentication mechanism */ - unsigned int authused; /* SASL auth mechanism used for the connection */ char *apoptimestamp; /* APOP timestamp from the server greeting */ bool tls_supported; /* StartTLS capability supported by server */ - bool mutual_auth; /* Mutual authentication enabled (GSSAPI only) */ }; extern const struct Curl_handler Curl_handler_pop3; diff --git a/Utilities/cmcurl/lib/progress.c b/Utilities/cmcurl/lib/progress.c index f147ce7..b46e274 100644 --- a/Utilities/cmcurl/lib/progress.c +++ b/Utilities/cmcurl/lib/progress.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -25,9 +25,7 @@ #include "urldata.h" #include "sendf.h" #include "progress.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> +#include "curl_printf.h" /* Provide a string that is 2 + 1 + 2 + 1 + 2 = 8 letters long (plus the zero byte) */ diff --git a/Utilities/cmcurl/lib/rtsp.c b/Utilities/cmcurl/lib/rtsp.c index 029738d..c30afd3 100644 --- a/Utilities/cmcurl/lib/rtsp.c +++ b/Utilities/cmcurl/lib/rtsp.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -34,14 +34,12 @@ #include "progress.h" #include "rtsp.h" #include "rawstr.h" -#include "curl_memory.h" #include "select.h" #include "connect.h" +#include "curl_printf.h" -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - -/* The last #include file should be: */ +/* The last #include files should be: */ +#include "curl_memory.h" #include "memdebug.h" /* @@ -265,11 +263,10 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) * Since all RTSP requests are included here, there is no need to * support custom requests like HTTP. **/ - DEBUGASSERT((rtspreq > RTSPREQ_NONE && rtspreq < RTSPREQ_LAST)); data->set.opt_no_body = TRUE; /* most requests don't contain a body */ switch(rtspreq) { - case RTSPREQ_NONE: - failf(data, "Got invalid RTSP request: RTSPREQ_NONE"); + default: + failf(data, "Got invalid RTSP request"); return CURLE_BAD_FUNCTION_ARGUMENT; case RTSPREQ_OPTIONS: p_request = "OPTIONS"; @@ -325,7 +322,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) if(!p_session_id && (rtspreq & ~(RTSPREQ_OPTIONS | RTSPREQ_DESCRIBE | RTSPREQ_SETUP))) { failf(data, "Refusing to issue an RTSP request [%s] without a session ID.", - p_request ? p_request : ""); + p_request); return CURLE_BAD_FUNCTION_ARGUMENT; } @@ -443,8 +440,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) Curl_add_bufferf(req_buffer, "%s %s RTSP/1.0\r\n" /* Request Stream-URI RTSP/1.0 */ "CSeq: %ld\r\n", /* CSeq */ - (p_request ? p_request : ""), p_stream_uri, - rtsp->CSeq_sent); + p_request, p_stream_uri, rtsp->CSeq_sent); if(result) return result; @@ -498,8 +494,8 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) } else { - postsize = (data->set.postfieldsize != -1)? - data->set.postfieldsize: + postsize = (data->state.infilesize != -1)? + data->state.infilesize: (data->set.postfields? (curl_off_t)strlen(data->set.postfields):0); data->set.httpreq = HTTPREQ_POST; } diff --git a/Utilities/cmcurl/lib/security.c b/Utilities/cmcurl/lib/security.c index 508c7b4..014bbf1 100644 --- a/Utilities/cmcurl/lib/security.c +++ b/Utilities/cmcurl/lib/security.c @@ -7,10 +7,10 @@ * rewrite to work around the paragraph 2 in the BSD licenses as explained * below. * - * Copyright (c) 1998, 1999, 2013 Kungliga Tekniska Högskolan + * Copyright (c) 1998, 1999 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * - * Copyright (C) 2001 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2001 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * All rights reserved. * @@ -109,19 +109,12 @@ static char level_to_char(int level) { return 'P'; } -static const struct Curl_sec_client_mech * const mechs[] = { -#ifdef HAVE_GSSAPI - &Curl_krb5_client_mech, -#endif - NULL -}; - /* Send an FTP command defined by |message| and the optional arguments. The function returns the ftp_code. If an error occurs, -1 is returned. */ static int ftp_send_command(struct connectdata *conn, const char *message, ...) { int ftp_code; - ssize_t nread; + ssize_t nread=0; va_list args; char print_buffer[50]; @@ -129,11 +122,11 @@ static int ftp_send_command(struct connectdata *conn, const char *message, ...) vsnprintf(print_buffer, sizeof(print_buffer), message, args); va_end(args); - if(Curl_ftpsendf(conn, print_buffer) != CURLE_OK) { + if(Curl_ftpsendf(conn, print_buffer)) { ftp_code = -1; } else { - if(Curl_GetFTPResponse(&nread, conn, &ftp_code) != CURLE_OK) + if(Curl_GetFTPResponse(&nread, conn, &ftp_code)) ftp_code = -1; } @@ -147,20 +140,20 @@ static CURLcode socket_read(curl_socket_t fd, void *to, size_t len) { char *to_p = to; - CURLcode code; + CURLcode result; ssize_t nread; while(len > 0) { - code = Curl_read_plain(fd, to_p, len, &nread); - if(code == CURLE_OK) { + result = Curl_read_plain(fd, to_p, len, &nread); + if(!result) { len -= nread; to_p += nread; } else { /* FIXME: We are doing a busy wait */ - if(code == CURLE_AGAIN) + if(result == CURLE_AGAIN) continue; - return code; + return result; } } return CURLE_OK; @@ -175,20 +168,20 @@ socket_write(struct connectdata *conn, curl_socket_t fd, const void *to, size_t len) { const char *to_p = to; - CURLcode code; + CURLcode result; ssize_t written; while(len > 0) { - code = Curl_write_plain(conn, fd, to_p, len, &written); - if(code == CURLE_OK) { + result = Curl_write_plain(conn, fd, to_p, len, &written); + if(!result) { len -= written; to_p += written; } else { /* FIXME: We are doing a busy wait */ - if(code == CURLE_AGAIN) + if(result == CURLE_AGAIN) continue; - return code; + return result; } } return CURLE_OK; @@ -200,11 +193,11 @@ static CURLcode read_data(struct connectdata *conn, { int len; void* tmp; - CURLcode ret; + CURLcode result; - ret = socket_read(fd, &len, sizeof(len)); - if(ret != CURLE_OK) - return ret; + result = socket_read(fd, &len, sizeof(len)); + if(result) + return result; len = ntohl(len); tmp = realloc(buf->data, len); @@ -212,9 +205,9 @@ static CURLcode read_data(struct connectdata *conn, return CURLE_OUT_OF_MEMORY; buf->data = tmp; - ret = socket_read(fd, buf->data, len); - if(ret != CURLE_OK) - return ret; + result = socket_read(fd, buf->data, len); + if(result) + return result; buf->size = conn->mech->decode(conn->app_data, buf->data, len, conn->data_prot, conn); buf->index = 0; @@ -256,7 +249,7 @@ static ssize_t sec_recv(struct connectdata *conn, int sockindex, buffer += bytes_read; while(len > 0) { - if(read_data(conn, fd, &conn->in_buffer) != CURLE_OK) + if(read_data(conn, fd, &conn->in_buffer)) return -1; if(conn->in_buffer.size == 0) { if(bytes_read > 0) @@ -295,7 +288,7 @@ static void do_sec_send(struct connectdata *conn, curl_socket_t fd, prot_level = conn->command_prot; } bytes = conn->mech->encode(conn->app_data, from, length, prot_level, - (void**)&buffer, conn); + (void**)&buffer); if(!buffer || bytes <= 0) return; /* error */ @@ -332,7 +325,6 @@ static void do_sec_send(struct connectdata *conn, curl_socket_t fd, static ssize_t sec_write(struct connectdata *conn, curl_socket_t fd, const char *buffer, size_t length) { - /* FIXME: Check for overflow */ ssize_t tx = 0, len = conn->buffer_size; len -= conn->mech->overhead(conn->app_data, conn->data_prot, @@ -340,10 +332,9 @@ static ssize_t sec_write(struct connectdata *conn, curl_socket_t fd, if(len <= 0) len = length; while(length) { - if(len >= 0 || length < (size_t)len) { - /* FIXME: Check for overflow. */ + if(length < (size_t)len) len = length; - } + do_sec_send(conn, fd, buffer, curlx_sztosi(len)); length -= len; buffer += len; @@ -368,7 +359,7 @@ int Curl_sec_read_msg(struct connectdata *conn, char *buffer, int */ int decoded_len; char *buf; - int ret_code; + int ret_code = 0; size_t decoded_sz = 0; CURLcode error; @@ -397,13 +388,13 @@ int Curl_sec_read_msg(struct connectdata *conn, char *buffer, } buf[decoded_len] = '\0'; - DEBUGASSERT(decoded_len > 3); - if(buf[3] == '-') - ret_code = 0; - else { - /* Check for error? */ - sscanf(buf, "%d", &ret_code); - } + if(decoded_len <= 3) + /* suspiciously short */ + return 0; + + if(buf[3] != '-') + /* safe to ignore return code */ + (void)sscanf(buf, "%d", &ret_code); if(buf[decoded_len - 1] == '\n') buf[decoded_len - 1] = '\0'; @@ -446,8 +437,8 @@ static int sec_set_protection_level(struct connectdata *conn) pbsz = strstr(conn->data->state.buffer, "PBSZ="); if(pbsz) { - /* FIXME: Checks for errors in sscanf? */ - sscanf(pbsz, "PBSZ=%u", &buffer_size); + /* ignore return code, use default value if it fails */ + (void)sscanf(pbsz, "PBSZ=%u", &buffer_size); if(buffer_size < conn->buffer_size) conn->buffer_size = buffer_size; } @@ -486,72 +477,63 @@ static CURLcode choose_mech(struct connectdata *conn) { int ret; struct SessionHandle *data = conn->data; - const struct Curl_sec_client_mech * const *mech; void *tmp_allocation; - const char *mech_name; - - for(mech = mechs; (*mech); ++mech) { - mech_name = (*mech)->name; - /* We have no mechanism with a NULL name but keep this check */ - DEBUGASSERT(mech_name != NULL); - if(mech_name == NULL) { - infof(data, "Skipping mechanism with empty name (%p)\n", (void *)mech); - continue; - } - tmp_allocation = realloc(conn->app_data, (*mech)->size); - if(tmp_allocation == NULL) { - failf(data, "Failed realloc of size %u", (*mech)->size); - mech = NULL; - return CURLE_OUT_OF_MEMORY; - } - conn->app_data = tmp_allocation; + const struct Curl_sec_client_mech *mech = &Curl_krb5_client_mech; - if((*mech)->init) { - ret = (*mech)->init(conn->app_data); - if(ret != 0) { - infof(data, "Failed initialization for %s. Skipping it.\n", mech_name); - continue; - } + tmp_allocation = realloc(conn->app_data, mech->size); + if(tmp_allocation == NULL) { + failf(data, "Failed realloc of size %u", mech->size); + mech = NULL; + return CURLE_OUT_OF_MEMORY; + } + conn->app_data = tmp_allocation; + + if(mech->init) { + ret = mech->init(conn->app_data); + if(ret) { + infof(data, "Failed initialization for %s. Skipping it.\n", + mech->name); + return CURLE_FAILED_INIT; } + } - infof(data, "Trying mechanism %s...\n", mech_name); - ret = ftp_send_command(conn, "AUTH %s", mech_name); - if(ret < 0) - /* FIXME: This error is too generic but it is OK for now. */ - return CURLE_COULDNT_CONNECT; - - if(ret/100 != 3) { - switch(ret) { - case 504: - infof(data, "Mechanism %s is not supported by the server (server " - "returned ftp code: 504).\n", mech_name); - break; - case 534: - infof(data, "Mechanism %s was rejected by the server (server returned " - "ftp code: 534).\n", mech_name); - break; - default: - if(ret/100 == 5) { - infof(data, "server does not support the security extensions\n"); - return CURLE_USE_SSL_FAILED; - } - break; + infof(data, "Trying mechanism %s...\n", mech->name); + ret = ftp_send_command(conn, "AUTH %s", mech->name); + if(ret < 0) + /* FIXME: This error is too generic but it is OK for now. */ + return CURLE_COULDNT_CONNECT; + + if(ret/100 != 3) { + switch(ret) { + case 504: + infof(data, "Mechanism %s is not supported by the server (server " + "returned ftp code: 504).\n", mech->name); + break; + case 534: + infof(data, "Mechanism %s was rejected by the server (server returned " + "ftp code: 534).\n", mech->name); + break; + default: + if(ret/100 == 5) { + infof(data, "server does not support the security extensions\n"); + return CURLE_USE_SSL_FAILED; } - continue; + break; } + return CURLE_LOGIN_DENIED; + } - /* Authenticate */ - ret = (*mech)->auth(conn->app_data, conn); + /* Authenticate */ + ret = mech->auth(conn->app_data, conn); - if(ret == AUTH_CONTINUE) - continue; - else if(ret != AUTH_OK) { + if(ret != AUTH_CONTINUE) { + if(ret != AUTH_OK) { /* Mechanism has dumped the error to stderr, don't error here. */ return -1; } DEBUGASSERT(ret == AUTH_OK); - conn->mech = *mech; + conn->mech = mech; conn->sec_complete = 1; conn->recv[FIRSTSOCKET] = sec_recv; conn->send[FIRSTSOCKET] = sec_send; @@ -561,10 +543,9 @@ static CURLcode choose_mech(struct connectdata *conn) /* Set the requested protection level */ /* BLOCKING */ (void)sec_set_protection_level(conn); - break; } - return mech != NULL ? CURLE_OK : CURLE_FAILED_INIT; + return CURLE_OK; } CURLcode @@ -579,10 +560,8 @@ Curl_sec_end(struct connectdata *conn) { if(conn->mech != NULL && conn->mech->end) conn->mech->end(conn->app_data); - if(conn->app_data) { - free(conn->app_data); - conn->app_data = NULL; - } + free(conn->app_data); + conn->app_data = NULL; if(conn->in_buffer.data) { free(conn->in_buffer.data); conn->in_buffer.data = NULL; diff --git a/Utilities/cmcurl/lib/select.c b/Utilities/cmcurl/lib/select.c index 03c93f3..6eff070 100644 --- a/Utilities/cmcurl/lib/select.c +++ b/Utilities/cmcurl/lib/select.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -39,6 +39,10 @@ #include <dos.h> /* delay() */ #endif +#ifdef __VXWORKS__ +#include <strings.h> /* bzero() in FD_SET */ +#endif + #include <curl/curl.h> #include "urldata.h" @@ -155,7 +159,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 timeval initial_tv = {0, 0}; int pending_ms = 0; int error; int r; @@ -389,7 +393,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 timeval initial_tv = {0, 0}; bool fds_none = TRUE; unsigned int i; int pending_ms = 0; @@ -569,6 +573,6 @@ int tpf_select_libcurl(int maxfds, fd_set* reads, fd_set* writes, rc = tpf_select_bsd(maxfds, reads, writes, excepts, tv); tpf_process_signals(); - return(rc); + return rc; } #endif /* TPF */ diff --git a/Utilities/cmcurl/lib/sendf.c b/Utilities/cmcurl/lib/sendf.c index 4a87c79..5f39d1f 100644 --- a/Utilities/cmcurl/lib/sendf.c +++ b/Utilities/cmcurl/lib/sendf.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -31,14 +31,11 @@ #include "ssh.h" #include "multiif.h" #include "non-ascii.h" - -#define _MPRINTF_REPLACE /* use the internal *printf() functions */ -#include <curl/mprintf.h> - -#include "curl_memory.h" +#include "curl_printf.h" #include "strerror.h" -/* The last #include file should be: */ +/* The last #include files should be: */ +#include "curl_memory.h" #include "memdebug.h" #ifdef CURL_DO_LINEEND_CONV @@ -55,7 +52,7 @@ static size_t convert_lineends(struct SessionHandle *data, /* sanity check */ if((startPtr == NULL) || (size < 1)) { - return(size); + return size; } if(data->state.prev_block_had_trailing_cr) { @@ -117,9 +114,9 @@ static size_t convert_lineends(struct SessionHandle *data, /* tidy up by null terminating the now shorter data */ *outPtr = '\0'; - return(outPtr - startPtr); + return (outPtr - startPtr); } - return(size); + return size; } #endif /* CURL_DO_LINEEND_CONV */ @@ -174,7 +171,7 @@ CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *conn, struct SessionHandle *data = conn->data; ssize_t bytes_written; size_t write_len; - CURLcode res = CURLE_OK; + CURLcode result = CURLE_OK; char *s; char *sptr; va_list ap; @@ -190,9 +187,9 @@ CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *conn, for(;;) { /* Write the buffer to the socket */ - res = Curl_write(conn, sockfd, sptr, write_len, &bytes_written); + result = Curl_write(conn, sockfd, sptr, write_len, &bytes_written); - if(CURLE_OK != res) + if(result) break; if(data->set.verbose) @@ -210,7 +207,7 @@ CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *conn, free(s); /* free the output string */ - return res; + return result; } /* @@ -227,10 +224,10 @@ CURLcode Curl_write(struct connectdata *conn, ssize_t *written) { ssize_t bytes_written; - CURLcode curlcode = CURLE_OK; + CURLcode result = CURLE_OK; int num = (sockfd == conn->sock[SECONDARYSOCKET]); - bytes_written = conn->send[num](conn, num, mem, len, &curlcode); + bytes_written = conn->send[num](conn, num, mem, len, &result); *written = bytes_written; if(bytes_written >= 0) @@ -238,7 +235,7 @@ CURLcode Curl_write(struct connectdata *conn, return CURLE_OK; /* handle CURLE_AGAIN or a send failure */ - switch(curlcode) { + switch(result) { case CURLE_AGAIN: *written = 0; return CURLE_OK; @@ -249,7 +246,7 @@ CURLcode Curl_write(struct connectdata *conn, default: /* we got a specific curlcode, forward it */ - return curlcode; + return result; } } @@ -300,14 +297,14 @@ CURLcode Curl_write_plain(struct connectdata *conn, ssize_t *written) { ssize_t bytes_written; - CURLcode retcode; + CURLcode result; int num = (sockfd == conn->sock[SECONDARYSOCKET]); - bytes_written = Curl_send_plain(conn, num, mem, len, &retcode); + bytes_written = Curl_send_plain(conn, num, mem, len, &result); *written = bytes_written; - return retcode; + return result; } ssize_t Curl_recv_plain(struct connectdata *conn, int num, char *buf, @@ -374,25 +371,21 @@ static CURLcode pausewrite(struct SessionHandle *data, } -/* Curl_client_write() sends data to the write callback(s) - - The bit pattern defines to what "streams" to write to. Body and/or header. - The defines are in sendf.h of course. - - If CURL_DO_LINEEND_CONV is enabled, data is converted IN PLACE to the - local character encoding. This is a problem and should be changed in - the future to leave the original data alone. +/* Curl_client_chop_write() writes chunks of data not larger than + * CURL_MAX_WRITE_SIZE via client write callback(s) and + * takes care of pause requests from the callbacks. */ -CURLcode Curl_client_write(struct connectdata *conn, - int type, - char *ptr, - size_t len) +CURLcode Curl_client_chop_write(struct connectdata *conn, + int type, + char * ptr, + size_t len) { struct SessionHandle *data = conn->data; - size_t wrote; + curl_write_callback writeheader = NULL; + curl_write_callback writebody = NULL; - if(0 == len) - len = strlen(ptr); + if(!len) + return CURLE_OK; /* If reading is actually paused, we're forced to append this chunk of data to the already held data, but only if it is the same type as otherwise it @@ -417,78 +410,107 @@ CURLcode Curl_client_write(struct connectdata *conn, /* update the pointer and the size */ data->state.tempwrite = newptr; data->state.tempwritesize = newlen; - return CURLE_OK; } - if(type & CLIENTWRITE_BODY) { - if((conn->handler->protocol&PROTO_FAMILY_FTP) && - conn->proto.ftpc.transfertype == 'A') { - /* convert from the network encoding */ - CURLcode rc = Curl_convert_from_network(data, ptr, len); - /* Curl_convert_from_network calls failf if unsuccessful */ - if(rc) - return rc; + /* Determine the callback(s) to use. */ + if(type & CLIENTWRITE_BODY) + writebody = data->set.fwrite_func; + if((type & CLIENTWRITE_HEADER) && + (data->set.fwrite_header || data->set.writeheader)) { + /* + * Write headers to the same callback or to the especially setup + * header callback function (added after version 7.7.1). + */ + writeheader = + data->set.fwrite_header? data->set.fwrite_header: data->set.fwrite_func; + } -#ifdef CURL_DO_LINEEND_CONV - /* convert end-of-line markers */ - len = convert_lineends(data, ptr, len); -#endif /* CURL_DO_LINEEND_CONV */ - } - /* If the previous block of data ended with CR and this block of data is - just a NL, then the length might be zero */ - if(len) { - wrote = data->set.fwrite_func(ptr, 1, len, data->set.out); - } - else { - wrote = len; - } + /* Chop data, write chunks. */ + while(len) { + size_t chunklen = len <= CURL_MAX_WRITE_SIZE? len: CURL_MAX_WRITE_SIZE; + + if(writebody) { + size_t wrote = writebody(ptr, 1, chunklen, data->set.out); - if(CURL_WRITEFUNC_PAUSE == wrote) { - if(conn->handler->flags & PROTOPT_NONETWORK) { - /* Protocols that work without network cannot be paused. This is - actually only FILE:// just now, and it can't pause since the - transfer isn't done using the "normal" procedure. */ - failf(data, "Write callback asked for PAUSE when not supported!"); + if(CURL_WRITEFUNC_PAUSE == wrote) { + if(conn->handler->flags & PROTOPT_NONETWORK) { + /* Protocols that work without network cannot be paused. This is + actually only FILE:// just now, and it can't pause since the + transfer isn't done using the "normal" procedure. */ + failf(data, "Write callback asked for PAUSE when not supported!"); + return CURLE_WRITE_ERROR; + } + else + return pausewrite(data, type, ptr, len); + } + else if(wrote != chunklen) { + failf(data, "Failed writing body (%zu != %zu)", wrote, chunklen); return CURLE_WRITE_ERROR; } - else - return pausewrite(data, type, ptr, len); } - else if(wrote != len) { - failf(data, "Failed writing body (%zu != %zu)", wrote, len); - return CURLE_WRITE_ERROR; - } - } - if((type & CLIENTWRITE_HEADER) && - (data->set.fwrite_header || data->set.writeheader) ) { - /* - * Write headers to the same callback or to the especially setup - * header callback function (added after version 7.7.1). - */ - curl_write_callback writeit= - data->set.fwrite_header?data->set.fwrite_header:data->set.fwrite_func; - - /* Note: The header is in the host encoding - regardless of the ftp transfer mode (ASCII/Image) */ - - wrote = writeit(ptr, 1, len, data->set.writeheader); - if(CURL_WRITEFUNC_PAUSE == wrote) - /* here we pass in the HEADER bit only since if this was body as well - then it was passed already and clearly that didn't trigger the pause, - so this is saved for later with the HEADER bit only */ - return pausewrite(data, CLIENTWRITE_HEADER, ptr, len); - - if(wrote != len) { - failf (data, "Failed writing header"); - return CURLE_WRITE_ERROR; + if(writeheader) { + size_t wrote = writeheader(ptr, 1, chunklen, data->set.writeheader); + + if(CURL_WRITEFUNC_PAUSE == wrote) + /* here we pass in the HEADER bit only since if this was body as well + then it was passed already and clearly that didn't trigger the + pause, so this is saved for later with the HEADER bit only */ + return pausewrite(data, CLIENTWRITE_HEADER, ptr, len); + + if(wrote != chunklen) { + failf (data, "Failed writing header"); + return CURLE_WRITE_ERROR; + } } + + ptr += chunklen; + len -= chunklen; } return CURLE_OK; } + +/* Curl_client_write() sends data to the write callback(s) + + The bit pattern defines to what "streams" to write to. Body and/or header. + The defines are in sendf.h of course. + + If CURL_DO_LINEEND_CONV is enabled, data is converted IN PLACE to the + local character encoding. This is a problem and should be changed in + the future to leave the original data alone. + */ +CURLcode Curl_client_write(struct connectdata *conn, + int type, + char *ptr, + size_t len) +{ + struct SessionHandle *data = conn->data; + + if(0 == len) + len = strlen(ptr); + + /* FTP data may need conversion. */ + if((type & CLIENTWRITE_BODY) && + (conn->handler->protocol & PROTO_FAMILY_FTP) && + conn->proto.ftpc.transfertype == 'A') { + /* convert from the network encoding */ + CURLcode result = Curl_convert_from_network(data, ptr, len); + /* Curl_convert_from_network calls failf if unsuccessful */ + if(result) + return result; + +#ifdef CURL_DO_LINEEND_CONV + /* convert end-of-line markers */ + len = convert_lineends(data, ptr, len); +#endif /* CURL_DO_LINEEND_CONV */ + } + + return Curl_client_chop_write(conn, type, ptr, len); +} + CURLcode Curl_read_plain(curl_socket_t sockfd, char *buf, size_t bytesfromsocket, @@ -525,11 +547,11 @@ CURLcode Curl_read(struct connectdata *conn, /* connection data */ size_t sizerequested, /* max amount to read */ ssize_t *n) /* amount bytes read */ { - CURLcode curlcode = CURLE_RECV_ERROR; + CURLcode result = CURLE_RECV_ERROR; ssize_t nread = 0; size_t bytesfromsocket = 0; char *buffertofill = NULL; - bool pipelining = Curl_multi_pipeline_enabled(conn->data->multi); + bool pipelining = Curl_pipeline_wanted(conn->data->multi, CURLPIPE_HTTP1); /* Set 'num' to 0 or 1, depending on which socket that has been sent here. If it is the second socket, we set num to 1. Otherwise to 0. This lets @@ -564,9 +586,9 @@ CURLcode Curl_read(struct connectdata *conn, /* connection data */ buffertofill = buf; } - nread = conn->recv[num](conn, num, buffertofill, bytesfromsocket, &curlcode); + nread = conn->recv[num](conn, num, buffertofill, bytesfromsocket, &result); if(nread < 0) - return curlcode; + return result; if(pipelining) { memcpy(buf, conn->master_buffer, nread); @@ -661,11 +683,13 @@ int Curl_debug(struct SessionHandle *data, curl_infotype type, switch (type) { case CURLINFO_HEADER_IN: w = "Header"; + /* FALLTHROUGH */ case CURLINFO_DATA_IN: t = "from"; break; case CURLINFO_HEADER_OUT: w = "Header"; + /* FALLTHROUGH */ case CURLINFO_DATA_OUT: t = "to"; break; diff --git a/Utilities/cmcurl/lib/sendf.h b/Utilities/cmcurl/lib/sendf.h index 39489e4..86f06cf 100644 --- a/Utilities/cmcurl/lib/sendf.h +++ b/Utilities/cmcurl/lib/sendf.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -51,8 +51,10 @@ void Curl_failf(struct SessionHandle *, const char *fmt, ...); #define CLIENTWRITE_HEADER (1<<1) #define CLIENTWRITE_BOTH (CLIENTWRITE_BODY|CLIENTWRITE_HEADER) +CURLcode Curl_client_chop_write(struct connectdata *conn, int type, char *ptr, + size_t len) WARN_UNUSED_RESULT; CURLcode Curl_client_write(struct connectdata *conn, int type, char *ptr, - size_t len); + size_t len) WARN_UNUSED_RESULT; /* internal read-function, does plain socket only */ CURLcode Curl_read_plain(curl_socket_t sockfd, diff --git a/Utilities/cmcurl/lib/setup-os400.h b/Utilities/cmcurl/lib/setup-os400.h index 0331464..fae8567 100644 --- a/Utilities/cmcurl/lib/setup-os400.h +++ b/Utilities/cmcurl/lib/setup-os400.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -37,7 +37,6 @@ typedef unsigned long u_int32_t; #include <sys/socket.h> #include <netdb.h> -#include <qsossl.h> #include <gskssl.h> #include <qsoasync.h> #include <gssapi.h> @@ -57,21 +56,6 @@ extern int Curl_getnameinfo_a(const struct sockaddr * sa, #define getnameinfo Curl_getnameinfo_a -/* SSL wrappers. */ - -extern int Curl_SSL_Init_Application_a(SSLInitApp * init_app); -#define SSL_Init_Application Curl_SSL_Init_Application_a - - -extern int Curl_SSL_Init_a(SSLInit * init); -#define SSL_Init Curl_SSL_Init_a - - -extern char * Curl_SSL_Strerror_a(int sslreturnvalue, - SSLErrorMsg * serrmsgp); -#define SSL_Strerror Curl_SSL_Strerror_a - - /* GSKit wrappers. */ extern int Curl_gsk_environment_open(gsk_handle * my_env_handle); diff --git a/Utilities/cmcurl/lib/setup-vms.h b/Utilities/cmcurl/lib/setup-vms.h index f5eedf7..520a35d 100644 --- a/Utilities/cmcurl/lib/setup-vms.h +++ b/Utilities/cmcurl/lib/setup-vms.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -203,6 +203,19 @@ char * unix_path; #define CRYPTO_cleanup_all_ex_data CRYPTO_CLEANUP_ALL_EX_DATA #define CRYPTO_free CRYPTO_FREE #define CRYPTO_malloc CRYPTO_MALLOC +#define CONF_modules_load_file CONF_MODULES_LOAD_FILE +#ifdef __VAX +# ifdef VMS_OLD_SSL + /* Ancient OpenSSL on VAX/VMS missing this constant */ +# define CONF_MFLAGS_IGNORE_MISSING_FILE 0x10 +# undef CONF_modules_load_file + static int CONF_modules_load_file(const char *filename, + const char *appname, + unsigned long flags) { + return 1; + } +# endif +#endif #define DES_ecb_encrypt DES_ECB_ENCRYPT #define DES_set_key DES_SET_KEY #define DES_set_odd_parity DES_SET_ODD_PARITY @@ -228,6 +241,7 @@ char * unix_path; #define EVP_PKEY_free EVP_PKEY_FREE #define EVP_cleanup EVP_CLEANUP #define GENERAL_NAMES_free GENERAL_NAMES_FREE +#define i2d_X509_PUBKEY I2D_X509_PUBKEY #define MD4_Final MD4_FINAL #define MD4_Init MD4_INIT #define MD4_Update MD4_UPDATE @@ -235,6 +249,9 @@ char * unix_path; #define MD5_Init MD5_INIT #define MD5_Update MD5_UPDATE #define OPENSSL_add_all_algo_noconf OPENSSL_ADD_ALL_ALGO_NOCONF +#ifndef __VAX +#define OPENSSL_load_builtin_modules OPENSSL_LOAD_BUILTIN_MODULES +#endif #define PEM_read_X509 PEM_READ_X509 #define PEM_write_bio_X509 PEM_WRITE_BIO_X509 #define PKCS12_PBE_add PKCS12_PBE_ADD @@ -258,6 +275,7 @@ char * unix_path; #define SSL_CTX_set_cipher_list SSL_CTX_SET_CIPHER_LIST #define SSL_CTX_set_def_passwd_cb_ud SSL_CTX_SET_DEF_PASSWD_CB_UD #define SSL_CTX_set_default_passwd_cb SSL_CTX_SET_DEFAULT_PASSWD_CB +#define SSL_CTX_set_msg_callback SSL_CTX_SET_MSG_CALLBACK #define SSL_CTX_set_verify SSL_CTX_SET_VERIFY #define SSL_CTX_use_PrivateKey SSL_CTX_USE_PRIVATEKEY #define SSL_CTX_use_PrivateKey_file SSL_CTX_USE_PRIVATEKEY_FILE @@ -274,6 +292,7 @@ char * unix_path; #define SSL_get_peer_cert_chain SSL_GET_PEER_CERT_CHAIN #define SSL_get_peer_certificate SSL_GET_PEER_CERTIFICATE #define SSL_get_privatekey SSL_GET_PRIVATEKEY +#define SSL_get_session SSL_GET_SESSION #define SSL_get_shutdown SSL_GET_SHUTDOWN #define SSL_get_verify_result SSL_GET_VERIFY_RESULT #define SSL_library_init SSL_LIBRARY_INIT @@ -286,14 +305,32 @@ char * unix_path; #define SSL_set_fd SSL_SET_FD #define SSL_set_session SSL_SET_SESSION #define SSL_shutdown SSL_SHUTDOWN +#define SSL_version SSL_VERSION #define SSL_write SSL_WRITE #define SSLeay SSLEAY #define SSLv23_client_method SSLV23_CLIENT_METHOD #define SSLv3_client_method SSLV3_CLIENT_METHOD #define TLSv1_client_method TLSV1_CLIENT_METHOD +#define UI_create_method UI_CREATE_METHOD +#define UI_destroy_method UI_DESTROY_METHOD +#define UI_get0_user_data UI_GET0_USER_DATA +#define UI_get_input_flags UI_GET_INPUT_FLAGS +#define UI_get_string_type UI_GET_STRING_TYPE +#define UI_create_method UI_CREATE_METHOD +#define UI_destroy_method UI_DESTROY_METHOD +#define UI_method_get_closer UI_METHOD_GET_CLOSER +#define UI_method_get_opener UI_METHOD_GET_OPENER +#define UI_method_get_reader UI_METHOD_GET_READER +#define UI_method_get_writer UI_METHOD_GET_WRITER +#define UI_method_set_closer UI_METHOD_SET_CLOSER +#define UI_method_set_opener UI_METHOD_SET_OPENER +#define UI_method_set_reader UI_METHOD_SET_READER +#define UI_method_set_writer UI_METHOD_SET_WRITER #define UI_OpenSSL UI_OPENSSL +#define UI_set_result UI_SET_RESULT #define X509V3_EXT_print X509V3_EXT_PRINT #define X509_EXTENSION_get_critical X509_EXTENSION_GET_CRITICAL +#define X509_EXTENSION_get_data X509_EXTENSION_GET_DATA #define X509_EXTENSION_get_object X509_EXTENSION_GET_OBJECT #define X509_LOOKUP_file X509_LOOKUP_FILE #define X509_NAME_ENTRY_get_data X509_NAME_ENTRY_GET_DATA @@ -318,6 +355,12 @@ char * unix_path; #define sk_pop SK_POP #define sk_pop_free SK_POP_FREE #define sk_value SK_VALUE +#ifdef __VAX +#define OPENSSL_NO_SHA256 +#endif +#define SHA256_Final SHA256_FINAL +#define SHA256_Init SHA256_INIT +#define SHA256_Update SHA256_UPDATE #define USE_UPPERCASE_GSSAPI 1 #define gss_seal GSS_SEAL @@ -383,7 +426,7 @@ char * unix_path; static void des_ecb_encrypt(const_des_cblock *input, des_cblock *output, - des_key_schedule ks,int enc) { + des_key_schedule ks, int enc) { DES_ECB_ENCRYPT(input, output, ks, enc); } #endif diff --git a/Utilities/cmcurl/lib/share.c b/Utilities/cmcurl/lib/share.c index b8b6bee..1720248 100644 --- a/Utilities/cmcurl/lib/share.c +++ b/Utilities/cmcurl/lib/share.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -35,9 +35,15 @@ CURLSH * curl_share_init(void) { struct Curl_share *share = calloc(1, sizeof(struct Curl_share)); - if(share) + if(share) { share->specifier |= (1<<CURL_LOCK_DATA_SHARE); + if(Curl_mk_dnscache(&share->hostcache)) { + free(share); + return NULL; + } + } + return share; } @@ -67,11 +73,6 @@ curl_share_setopt(CURLSH *sh, CURLSHoption option, ...) share->specifier |= (1<<type); switch( type ) { case CURL_LOCK_DATA_DNS: - if(!share->hostcache) { - share->hostcache = Curl_mk_dnscache(); - if(!share->hostcache) - res = CURLSHE_NOMEM; - } break; case CURL_LOCK_DATA_COOKIE: @@ -115,10 +116,6 @@ curl_share_setopt(CURLSH *sh, CURLSHoption option, ...) share->specifier &= ~(1<<type); switch( type ) { case CURL_LOCK_DATA_DNS: - if(share->hostcache) { - Curl_hash_destroy(share->hostcache); - share->hostcache = NULL; - } break; case CURL_LOCK_DATA_COOKIE: @@ -192,14 +189,10 @@ curl_share_cleanup(CURLSH *sh) return CURLSHE_IN_USE; } - if(share->hostcache) { - Curl_hash_destroy(share->hostcache); - share->hostcache = NULL; - } + Curl_hash_destroy(&share->hostcache); #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) - if(share->cookies) - Curl_cookie_cleanup(share->cookies); + Curl_cookie_cleanup(share->cookies); #endif #ifdef USE_SSL diff --git a/Utilities/cmcurl/lib/share.h b/Utilities/cmcurl/lib/share.h index 9a5128e..8e6629b 100644 --- a/Utilities/cmcurl/lib/share.h +++ b/Utilities/cmcurl/lib/share.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -44,7 +44,7 @@ struct Curl_share { curl_unlock_function unlockfunc; void *clientdata; - struct curl_hash *hostcache; + struct curl_hash hostcache; #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) struct CookieInfo *cookies; #endif diff --git a/Utilities/cmcurl/lib/slist.c b/Utilities/cmcurl/lib/slist.c index 3cac6ca..9c0b2a5 100644 --- a/Utilities/cmcurl/lib/slist.c +++ b/Utilities/cmcurl/lib/slist.c @@ -22,10 +22,10 @@ #include "curl_setup.h" -#include "curl_memory.h" #include "slist.h" -/* The last #include file should be: */ +/* The last #include files should be: */ +#include "curl_memory.h" #include "memdebug.h" /* returns last node in linked list */ diff --git a/Utilities/cmcurl/lib/smb.c b/Utilities/cmcurl/lib/smb.c new file mode 100644 index 0000000..d461a71 --- /dev/null +++ b/Utilities/cmcurl/lib/smb.c @@ -0,0 +1,976 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2014, Bill Nagel <wnagel@tycoint.com>, Exacq Technologies + * Copyright (C) 2015, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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" + +#if !defined(CURL_DISABLE_SMB) && defined(USE_NTLM) && \ + (CURL_SIZEOF_CURL_OFF_T > 4) + +#if !defined(USE_WINDOWS_SSPI) || defined(USE_WIN32_CRYPTO) + +#define BUILDING_CURL_SMB_C + +#ifdef HAVE_PROCESS_H +#include <process.h> +#define getpid _getpid +#endif + +#include "smb.h" +#include "urldata.h" +#include "sendf.h" +#include "multiif.h" +#include "connect.h" +#include "progress.h" +#include "transfer.h" +#include "vtls/vtls.h" +#include "curl_ntlm_core.h" +#include "escape.h" +#include "curl_endian.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +/* Local API functions */ +static CURLcode smb_setup_connection(struct connectdata *conn); +static CURLcode smb_connect(struct connectdata *conn, bool *done); +static CURLcode smb_connection_state(struct connectdata *conn, bool *done); +static CURLcode smb_request_state(struct connectdata *conn, bool *done); +static CURLcode smb_done(struct connectdata *conn, CURLcode status, + bool premature); +static CURLcode smb_disconnect(struct connectdata *conn, bool dead); +static int smb_getsock(struct connectdata *conn, curl_socket_t *socks, + int numsocks); +static CURLcode smb_parse_url_path(struct connectdata *conn); + +/* + * SMB handler interface + */ +const struct Curl_handler Curl_handler_smb = { + "SMB", /* scheme */ + smb_setup_connection, /* setup_connection */ + ZERO_NULL, /* do_it */ + smb_done, /* done */ + ZERO_NULL, /* do_more */ + smb_connect, /* connect_it */ + smb_connection_state, /* connecting */ + smb_request_state, /* doing */ + smb_getsock, /* proto_getsock */ + smb_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ + ZERO_NULL, /* perform_getsock */ + smb_disconnect, /* disconnect */ + ZERO_NULL, /* readwrite */ + PORT_SMB, /* defport */ + CURLPROTO_SMB, /* protocol */ + PROTOPT_NONE /* flags */ +}; + +#ifdef USE_SSL +/* + * SMBS handler interface + */ +const struct Curl_handler Curl_handler_smbs = { + "SMBS", /* scheme */ + smb_setup_connection, /* setup_connection */ + ZERO_NULL, /* do_it */ + smb_done, /* done */ + ZERO_NULL, /* do_more */ + smb_connect, /* connect_it */ + smb_connection_state, /* connecting */ + smb_request_state, /* doing */ + smb_getsock, /* proto_getsock */ + smb_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ + ZERO_NULL, /* perform_getsock */ + smb_disconnect, /* disconnect */ + ZERO_NULL, /* readwrite */ + PORT_SMBS, /* defport */ + CURLPROTO_SMBS, /* protocol */ + PROTOPT_SSL /* flags */ +}; +#endif + +#define MAX_PAYLOAD_SIZE 0x8000 +#define MAX_MESSAGE_SIZE (MAX_PAYLOAD_SIZE + 0x1000) +#define CLIENTNAME "curl" +#define SERVICENAME "?????" + +/* Append a string to an SMB message */ +#define MSGCAT(str) \ + strcpy(p, (str)); \ + p += strlen(str); + +/* Append a null-terminated string to an SMB message */ +#define MSGCATNULL(str) \ + strcpy(p, (str)); \ + p += strlen(str) + 1; + +/* SMB is mostly little endian */ +#if (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) || \ + defined(__OS400__) +static unsigned short smb_swap16(unsigned short x) +{ + return (x << 8) | ((x >> 8) & 0xff); +} + +static unsigned int smb_swap32(unsigned int x) +{ + return (x << 24) | ((x << 8) & 0xff0000) | ((x >> 8) & 0xff00) | + ((x >> 24) & 0xff); +} + +#ifdef HAVE_LONGLONG +static unsigned long long smb_swap64(unsigned long long x) +{ + return ((unsigned long long)smb_swap32(x) << 32) | smb_swap32(x >> 32); +} +#else +static unsigned __int64 smb_swap64(unsigned __int64 x) +{ + return ((unsigned __int64)smb_swap32(x) << 32) | smb_swap32(x >> 32); +} +#endif +#else +# define smb_swap16(x) (x) +# define smb_swap32(x) (x) +# define smb_swap64(x) (x) +#endif + +/* SMB request state */ +enum smb_req_state { + SMB_REQUESTING, + SMB_TREE_CONNECT, + SMB_OPEN, + SMB_DOWNLOAD, + SMB_UPLOAD, + SMB_CLOSE, + SMB_TREE_DISCONNECT, + SMB_DONE +}; + +/* SMB request data */ +struct smb_request { + enum smb_req_state state; + char *share; + char *path; + unsigned short tid; /* Even if we connect to the same tree as another */ + unsigned short fid; /* request, the tid will be different */ + CURLcode result; +}; + +static void conn_state(struct connectdata *conn, enum smb_conn_state newstate) +{ + struct smb_conn *smb = &conn->proto.smbc; +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) + /* For debug purposes */ + static const char * const names[] = { + "SMB_NOT_CONNECTED", + "SMB_CONNECTING", + "SMB_NEGOTIATE", + "SMB_SETUP", + "SMB_CONNECTED", + /* LAST */ + }; + + if(smb->state != newstate) + infof(conn->data, "SMB conn %p state change from %s to %s\n", + (void *)smb, names[smb->state], names[newstate]); +#endif + + smb->state = newstate; +} + +static void request_state(struct connectdata *conn, + enum smb_req_state newstate) +{ + struct smb_request *req = conn->data->req.protop; +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) + /* For debug purposes */ + static const char * const names[] = { + "SMB_REQUESTING", + "SMB_TREE_CONNECT", + "SMB_OPEN", + "SMB_DOWNLOAD", + "SMB_UPLOAD", + "SMB_CLOSE", + "SMB_TREE_DISCONNECT", + "SMB_DONE", + /* LAST */ + }; + + if(req->state != newstate) + infof(conn->data, "SMB request %p state change from %s to %s\n", + (void *)req, names[req->state], names[newstate]); +#endif + + req->state = newstate; +} + +static CURLcode smb_setup_connection(struct connectdata *conn) +{ + struct smb_request *req; + + /* Initialize the request state */ + conn->data->req.protop = req = calloc(1, sizeof(struct smb_request)); + if(!req) + return CURLE_OUT_OF_MEMORY; + + /* Parse the URL path */ + return smb_parse_url_path(conn); +} + +static CURLcode smb_connect(struct connectdata *conn, bool *done) +{ + struct smb_conn *smbc = &conn->proto.smbc; + char *slash; + + (void) done; + + /* Check we have a username and password to authenticate with */ + if(!conn->bits.user_passwd) + return CURLE_LOGIN_DENIED; + + /* Initialize the connection state */ + memset(smbc, 0, sizeof(*smbc)); + smbc->state = SMB_CONNECTING; + smbc->recv_buf = malloc(MAX_MESSAGE_SIZE); + if(!smbc->recv_buf) + return CURLE_OUT_OF_MEMORY; + + /* Multiple requests are allowed with this connection */ + connkeep(conn, "SMB default"); + + /* Parse the username, domain, and password */ + slash = strchr(conn->user, '/'); + if(!slash) + slash = strchr(conn->user, '\\'); + + if(slash) { + smbc->user = slash + 1; + smbc->domain = strdup(conn->user); + if(!smbc->domain) + return CURLE_OUT_OF_MEMORY; + smbc->domain[slash - conn->user] = 0; + } + else { + smbc->user = conn->user; + smbc->domain = strdup(conn->host.name); + if(!smbc->domain) + return CURLE_OUT_OF_MEMORY; + } + + return CURLE_OK; +} + +static CURLcode smb_recv_message(struct connectdata *conn, void **msg) +{ + struct smb_conn *smbc = &conn->proto.smbc; + char *buf = smbc->recv_buf; + ssize_t bytes_read; + size_t nbt_size; + size_t msg_size; + size_t len = MAX_MESSAGE_SIZE - smbc->got; + CURLcode result; + + result = Curl_read(conn, FIRSTSOCKET, buf + smbc->got, len, &bytes_read); + if(result) + return result; + + if(!bytes_read) + return CURLE_OK; + + smbc->got += bytes_read; + + /* Check for a 32-bit nbt header */ + if(smbc->got < sizeof(unsigned int)) + return CURLE_OK; + + nbt_size = Curl_read16_be((unsigned char *)(buf + sizeof(unsigned short))) + + sizeof(unsigned int); + if(smbc->got < nbt_size) + return CURLE_OK; + + msg_size = sizeof(struct smb_header); + if(nbt_size >= msg_size + 1) { + /* Add the word count */ + msg_size += 1 + ((unsigned char) buf[msg_size]) * sizeof(unsigned short); + if(nbt_size >= msg_size + sizeof(unsigned short)) { + /* Add the byte count */ + msg_size += sizeof(unsigned short) + + Curl_read16_le((unsigned char *)&buf[msg_size]); + if(nbt_size < msg_size) + return CURLE_READ_ERROR; + } + } + + *msg = buf; + + return CURLE_OK; +} + +static void smb_pop_message(struct connectdata *conn) +{ + struct smb_conn *smbc = &conn->proto.smbc; + + smbc->got = 0; +} + +static void smb_format_message(struct connectdata *conn, struct smb_header *h, + unsigned char cmd, size_t len) +{ + struct smb_conn *smbc = &conn->proto.smbc; + struct smb_request *req = conn->data->req.protop; + unsigned int pid; + + memset(h, 0, sizeof(*h)); + h->nbt_length = htons((unsigned short) (sizeof(*h) - sizeof(unsigned int) + + len)); + memcpy((char *)h->magic, "\xffSMB", 4); + h->command = cmd; + h->flags = SMB_FLAGS_CANONICAL_PATHNAMES | SMB_FLAGS_CASELESS_PATHNAMES; + h->flags2 = smb_swap16(SMB_FLAGS2_IS_LONG_NAME | SMB_FLAGS2_KNOWS_LONG_NAME); + h->uid = smb_swap16(smbc->uid); + h->tid = smb_swap16(req->tid); + pid = getpid(); + h->pid_high = smb_swap16((unsigned short)(pid >> 16)); + h->pid = smb_swap16((unsigned short) pid); +} + +static CURLcode smb_send(struct connectdata *conn, ssize_t len, + size_t upload_size) +{ + struct smb_conn *smbc = &conn->proto.smbc; + ssize_t bytes_written; + CURLcode result; + + result = Curl_write(conn, FIRSTSOCKET, conn->data->state.uploadbuffer, + len, &bytes_written); + if(result) + return result; + + if(bytes_written != len) { + smbc->send_size = len; + smbc->sent = bytes_written; + } + + smbc->upload_size = upload_size; + + return CURLE_OK; +} + +static CURLcode smb_flush(struct connectdata *conn) +{ + struct smb_conn *smbc = &conn->proto.smbc; + ssize_t bytes_written; + ssize_t len = smbc->send_size - smbc->sent; + CURLcode result; + + if(!smbc->send_size) + return CURLE_OK; + + result = Curl_write(conn, FIRSTSOCKET, + conn->data->state.uploadbuffer + smbc->sent, + len, &bytes_written); + if(result) + return result; + + if(bytes_written != len) + smbc->sent += bytes_written; + else + smbc->send_size = 0; + + return CURLE_OK; +} + +static CURLcode smb_send_message(struct connectdata *conn, unsigned char cmd, + const void *msg, size_t msg_len) +{ + smb_format_message(conn, (struct smb_header *)conn->data->state.uploadbuffer, + cmd, msg_len); + memcpy(conn->data->state.uploadbuffer + sizeof(struct smb_header), + msg, msg_len); + + return smb_send(conn, sizeof(struct smb_header) + msg_len, 0); +} + +static CURLcode smb_send_negotiate(struct connectdata *conn) +{ + const char *msg = "\x00\x0c\x00\x02NT LM 0.12"; + + return smb_send_message(conn, SMB_COM_NEGOTIATE, msg, 15); +} + +static CURLcode smb_send_setup(struct connectdata *conn) +{ + struct smb_conn *smbc = &conn->proto.smbc; + struct smb_setup msg; + char *p = msg.bytes; + unsigned char lm_hash[21]; + unsigned char lm[24]; + unsigned char nt_hash[21]; + unsigned char nt[24]; + + size_t byte_count = sizeof(lm) + sizeof(nt); + byte_count += strlen(smbc->user) + strlen(smbc->domain); + byte_count += strlen(OS) + strlen(CLIENTNAME) + 4; /* 4 null chars */ + if(byte_count > sizeof(msg.bytes)) + return CURLE_FILESIZE_EXCEEDED; + + Curl_ntlm_core_mk_lm_hash(conn->data, conn->passwd, lm_hash); + Curl_ntlm_core_lm_resp(lm_hash, smbc->challenge, lm); +#if USE_NTRESPONSES + Curl_ntlm_core_mk_nt_hash(conn->data, conn->passwd, nt_hash); + Curl_ntlm_core_lm_resp(nt_hash, smbc->challenge, nt); +#else + memset(nt, 0, sizeof(nt)); +#endif + + memset(&msg, 0, sizeof(msg)); + msg.word_count = SMB_WC_SETUP_ANDX; + msg.andx.command = SMB_COM_NO_ANDX_COMMAND; + msg.max_buffer_size = smb_swap16(MAX_MESSAGE_SIZE); + msg.max_mpx_count = smb_swap16(1); + msg.vc_number = smb_swap16(1); + msg.session_key = smb_swap32(smbc->session_key); + msg.capabilities = smb_swap32(SMB_CAP_LARGE_FILES); + msg.lengths[0] = smb_swap16(sizeof(lm)); + msg.lengths[1] = smb_swap16(sizeof(nt)); + memcpy(p, lm, sizeof(lm)); + p += sizeof(lm); + memcpy(p, nt, sizeof(nt)); + p += sizeof(nt); + MSGCATNULL(smbc->user); + MSGCATNULL(smbc->domain); + MSGCATNULL(OS); + MSGCATNULL(CLIENTNAME); + byte_count = p - msg.bytes; + msg.byte_count = smb_swap16((unsigned short)byte_count); + + return smb_send_message(conn, SMB_COM_SETUP_ANDX, &msg, + sizeof(msg) - sizeof(msg.bytes) + byte_count); +} + +static CURLcode smb_send_tree_connect(struct connectdata *conn) +{ + struct smb_request *req = conn->data->req.protop; + struct smb_tree_connect msg; + char *p = msg.bytes; + + size_t byte_count = strlen(conn->host.name) + strlen(req->share); + byte_count += strlen(SERVICENAME) + 5; /* 2 nulls and 3 backslashes */ + if(byte_count > sizeof(msg.bytes)) + return CURLE_FILESIZE_EXCEEDED; + + memset(&msg, 0, sizeof(msg)); + msg.word_count = SMB_WC_TREE_CONNECT_ANDX; + msg.andx.command = SMB_COM_NO_ANDX_COMMAND; + msg.pw_len = 0; + MSGCAT("\\\\"); + MSGCAT(conn->host.name); + MSGCAT("\\"); + MSGCATNULL(req->share); + MSGCATNULL(SERVICENAME); /* Match any type of service */ + byte_count = p - msg.bytes; + msg.byte_count = smb_swap16((unsigned short)byte_count); + + return smb_send_message(conn, SMB_COM_TREE_CONNECT_ANDX, &msg, + sizeof(msg) - sizeof(msg.bytes) + byte_count); +} + +static CURLcode smb_send_open(struct connectdata *conn) +{ + struct smb_request *req = conn->data->req.protop; + struct smb_nt_create msg; + size_t byte_count; + + if((strlen(req->path) + 1) > sizeof(msg.bytes)) + return CURLE_FILESIZE_EXCEEDED; + + memset(&msg, 0, sizeof(msg)); + msg.word_count = SMB_WC_NT_CREATE_ANDX; + msg.andx.command = SMB_COM_NO_ANDX_COMMAND; + byte_count = strlen(req->path); + msg.name_length = smb_swap16((unsigned short)byte_count); + msg.share_access = smb_swap32(SMB_FILE_SHARE_ALL); + if(conn->data->set.upload) { + msg.access = smb_swap32(SMB_GENERIC_READ | SMB_GENERIC_WRITE); + msg.create_disposition = smb_swap32(SMB_FILE_OVERWRITE_IF); + } + else { + msg.access = smb_swap32(SMB_GENERIC_READ); + msg.create_disposition = smb_swap32(SMB_FILE_OPEN); + } + msg.byte_count = smb_swap16((unsigned short) ++byte_count); + strcpy(msg.bytes, req->path); + + return smb_send_message(conn, SMB_COM_NT_CREATE_ANDX, &msg, + sizeof(msg) - sizeof(msg.bytes) + byte_count); +} + +static CURLcode smb_send_close(struct connectdata *conn) +{ + struct smb_request *req = conn->data->req.protop; + struct smb_close msg; + + memset(&msg, 0, sizeof(msg)); + msg.word_count = SMB_WC_CLOSE; + msg.fid = smb_swap16(req->fid); + + return smb_send_message(conn, SMB_COM_CLOSE, &msg, sizeof(msg)); +} + +static CURLcode smb_send_tree_disconnect(struct connectdata *conn) +{ + struct smb_tree_disconnect msg; + + memset(&msg, 0, sizeof(msg)); + + return smb_send_message(conn, SMB_COM_TREE_DISCONNECT, &msg, sizeof(msg)); +} + +static CURLcode smb_send_read(struct connectdata *conn) +{ + struct smb_request *req = conn->data->req.protop; + curl_off_t offset = conn->data->req.offset; + struct smb_read msg; + + memset(&msg, 0, sizeof(msg)); + msg.word_count = SMB_WC_READ_ANDX; + msg.andx.command = SMB_COM_NO_ANDX_COMMAND; + msg.fid = smb_swap16(req->fid); + msg.offset = smb_swap32((unsigned int) offset); + msg.offset_high = smb_swap32((unsigned int) (offset >> 32)); + msg.min_bytes = smb_swap16(MAX_PAYLOAD_SIZE); + msg.max_bytes = smb_swap16(MAX_PAYLOAD_SIZE); + + return smb_send_message(conn, SMB_COM_READ_ANDX, &msg, sizeof(msg)); +} + +static CURLcode smb_send_write(struct connectdata *conn) +{ + struct smb_write *msg = (struct smb_write *)conn->data->state.uploadbuffer; + struct smb_request *req = conn->data->req.protop; + curl_off_t offset = conn->data->req.offset; + + curl_off_t upload_size = conn->data->req.size - conn->data->req.bytecount; + if(upload_size >= MAX_PAYLOAD_SIZE - 1) /* There is one byte of padding */ + upload_size = MAX_PAYLOAD_SIZE - 1; + + memset(msg, 0, sizeof(*msg)); + msg->word_count = SMB_WC_WRITE_ANDX; + msg->andx.command = SMB_COM_NO_ANDX_COMMAND; + msg->fid = smb_swap16(req->fid); + msg->offset = smb_swap32((unsigned int) offset); + msg->offset_high = smb_swap32((unsigned int) (offset >> 32)); + msg->data_length = smb_swap16((unsigned short) upload_size); + msg->data_offset = smb_swap16(sizeof(*msg) - sizeof(unsigned int)); + msg->byte_count = smb_swap16((unsigned short) (upload_size + 1)); + + smb_format_message(conn, &msg->h, SMB_COM_WRITE_ANDX, + sizeof(*msg) - sizeof(msg->h) + (size_t) upload_size); + + return smb_send(conn, sizeof(*msg), (size_t) upload_size); +} + +static CURLcode smb_send_and_recv(struct connectdata *conn, void **msg) +{ + struct smb_conn *smbc = &conn->proto.smbc; + CURLcode result; + + /* Check if there is data in the transfer buffer */ + if(!smbc->send_size && smbc->upload_size) { + int nread = smbc->upload_size > BUFSIZE ? BUFSIZE : + (int) smbc->upload_size; + conn->data->req.upload_fromhere = conn->data->state.uploadbuffer; + result = Curl_fillreadbuffer(conn, nread, &nread); + if(result && result != CURLE_AGAIN) + return result; + if(!nread) + return CURLE_OK; + + smbc->upload_size -= nread; + smbc->send_size = nread; + smbc->sent = 0; + } + + /* Check if there is data to send */ + if(smbc->send_size) { + result = smb_flush(conn); + if(result) + return result; + } + + /* Check if there is still data to be sent */ + if(smbc->send_size || smbc->upload_size) + return CURLE_AGAIN; + + return smb_recv_message(conn, msg); +} + +static CURLcode smb_connection_state(struct connectdata *conn, bool *done) +{ + struct smb_conn *smbc = &conn->proto.smbc; + struct smb_negotiate_response *nrsp; + struct smb_header *h; + CURLcode result; + void *msg = NULL; + + if(smbc->state == SMB_CONNECTING) { +#ifdef USE_SSL + if((conn->handler->flags & PROTOPT_SSL)) { + bool ssl_done; + result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &ssl_done); + if(result && result != CURLE_AGAIN) + return result; + if(!ssl_done) + return CURLE_OK; + } +#endif + + result = smb_send_negotiate(conn); + if(result) { + connclose(conn, "SMB: failed to send negotiate message"); + return result; + } + + conn_state(conn, SMB_NEGOTIATE); + } + + /* Send the previous message and check for a response */ + result = smb_send_and_recv(conn, &msg); + if(result && result != CURLE_AGAIN) { + connclose(conn, "SMB: failed to communicate"); + return result; + } + + if(!msg) + return CURLE_OK; + + h = msg; + + switch(smbc->state) { + case SMB_NEGOTIATE: + if(h->status) { + connclose(conn, "SMB: negotiation failed"); + return CURLE_COULDNT_CONNECT; + } + nrsp = msg; + memcpy(smbc->challenge, nrsp->bytes, sizeof(smbc->challenge)); + smbc->session_key = smb_swap32(nrsp->session_key); + result = smb_send_setup(conn); + if(result) { + connclose(conn, "SMB: failed to send setup message"); + return result; + } + conn_state(conn, SMB_SETUP); + break; + + case SMB_SETUP: + if(h->status) { + connclose(conn, "SMB: authentication failed"); + return CURLE_LOGIN_DENIED; + } + smbc->uid = smb_swap16(h->uid); + conn_state(conn, SMB_CONNECTED); + *done = true; + break; + + default: + smb_pop_message(conn); + return CURLE_OK; /* ignore */ + } + + smb_pop_message(conn); + + return CURLE_OK; +} + +static CURLcode smb_request_state(struct connectdata *conn, bool *done) +{ + struct smb_request *req = conn->data->req.protop; + struct smb_header *h; + enum smb_req_state next_state = SMB_DONE; + unsigned short len; + unsigned short off; + CURLcode result; + void *msg = NULL; + + /* Start the request */ + if(req->state == SMB_REQUESTING) { + result = smb_send_tree_connect(conn); + if(result) { + connclose(conn, "SMB: failed to send tree connect message"); + return result; + } + + request_state(conn, SMB_TREE_CONNECT); + } + + /* Send the previous message and check for a response */ + result = smb_send_and_recv(conn, &msg); + if(result && result != CURLE_AGAIN) { + connclose(conn, "SMB: failed to communicate"); + return result; + } + + if(!msg) + return CURLE_OK; + + h = msg; + + switch(req->state) { + case SMB_TREE_CONNECT: + if(h->status) { + req->result = CURLE_REMOTE_FILE_NOT_FOUND; + if(h->status == smb_swap32(SMB_ERR_NOACCESS)) + req->result = CURLE_REMOTE_ACCESS_DENIED; + break; + } + req->tid = smb_swap16(h->tid); + next_state = SMB_OPEN; + break; + + case SMB_OPEN: + if(h->status) { + req->result = CURLE_REMOTE_FILE_NOT_FOUND; + next_state = SMB_TREE_DISCONNECT; + break; + } + req->fid = smb_swap16(((struct smb_nt_create_response *)msg)->fid); + conn->data->req.offset = 0; + if(conn->data->set.upload) { + conn->data->req.size = conn->data->state.infilesize; + Curl_pgrsSetUploadSize(conn->data, conn->data->req.size); + next_state = SMB_UPLOAD; + } + else { + conn->data->req.size = + smb_swap64(((struct smb_nt_create_response *)msg)->end_of_file); + Curl_pgrsSetDownloadSize(conn->data, conn->data->req.size); + next_state = SMB_DOWNLOAD; + } + break; + + case SMB_DOWNLOAD: + if(h->status) { + req->result = CURLE_RECV_ERROR; + next_state = SMB_CLOSE; + break; + } + len = Curl_read16_le(((unsigned char *) msg) + + sizeof(struct smb_header) + 11); + off = Curl_read16_le(((unsigned char *) msg) + + sizeof(struct smb_header) + 13); + if(len > 0) { + struct smb_conn *smbc = &conn->proto.smbc; + if(off + sizeof(unsigned int) + len > smbc->got) { + failf(conn->data, "Invalid input packet"); + result = CURLE_RECV_ERROR; + } + else + result = Curl_client_write(conn, CLIENTWRITE_BODY, + (char *)msg + off + sizeof(unsigned int), + len); + if(result) { + req->result = result; + next_state = SMB_CLOSE; + break; + } + } + conn->data->req.bytecount += len; + conn->data->req.offset += len; + Curl_pgrsSetDownloadCounter(conn->data, conn->data->req.bytecount); + next_state = (len < MAX_PAYLOAD_SIZE) ? SMB_CLOSE : SMB_DOWNLOAD; + break; + + case SMB_UPLOAD: + if(h->status) { + req->result = CURLE_UPLOAD_FAILED; + next_state = SMB_CLOSE; + break; + } + len = Curl_read16_le(((unsigned char *) msg) + + sizeof(struct smb_header) + 5); + conn->data->req.bytecount += len; + conn->data->req.offset += len; + Curl_pgrsSetUploadCounter(conn->data, conn->data->req.bytecount); + if(conn->data->req.bytecount >= conn->data->req.size) + next_state = SMB_CLOSE; + else + next_state = SMB_UPLOAD; + break; + + case SMB_CLOSE: + /* We don't care if the close failed, proceed to tree disconnect anyway */ + next_state = SMB_TREE_DISCONNECT; + break; + + case SMB_TREE_DISCONNECT: + next_state = SMB_DONE; + break; + + default: + smb_pop_message(conn); + return CURLE_OK; /* ignore */ + } + + smb_pop_message(conn); + + switch(next_state) { + case SMB_OPEN: + result = smb_send_open(conn); + break; + + case SMB_DOWNLOAD: + result = smb_send_read(conn); + break; + + case SMB_UPLOAD: + result = smb_send_write(conn); + break; + + case SMB_CLOSE: + result = smb_send_close(conn); + break; + + case SMB_TREE_DISCONNECT: + result = smb_send_tree_disconnect(conn); + break; + + case SMB_DONE: + result = req->result; + *done = true; + break; + + default: + break; + } + + if(result) { + connclose(conn, "SMB: failed to send message"); + return result; + } + + request_state(conn, next_state); + + return CURLE_OK; +} + +static CURLcode smb_done(struct connectdata *conn, CURLcode status, + bool premature) +{ + struct smb_request *req = conn->data->req.protop; + + (void) premature; + + Curl_safefree(req->share); + Curl_safefree(conn->data->req.protop); + + return status; +} + +static CURLcode smb_disconnect(struct connectdata *conn, bool dead) +{ + struct smb_conn *smbc = &conn->proto.smbc; + struct smb_request *req = conn->data->req.protop; + + (void) dead; + + Curl_safefree(smbc->domain); + Curl_safefree(smbc->recv_buf); + + /* smb_done is not always called, so cleanup the request */ + if(req) { + Curl_safefree(req->share); + Curl_safefree(conn->data->req.protop); + } + + return CURLE_OK; +} + +static int smb_getsock(struct connectdata *conn, curl_socket_t *socks, + int numsocks) +{ + struct smb_conn *smbc = &conn->proto.smbc; + + if(!numsocks) + return GETSOCK_BLANK; + + socks[0] = conn->sock[FIRSTSOCKET]; + + if(smbc->send_size || smbc->upload_size) + return GETSOCK_WRITESOCK(0); + + return GETSOCK_READSOCK(0); +} + +static CURLcode smb_parse_url_path(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + struct smb_request *req = data->req.protop; + char *path; + char *slash; + + /* URL decode the path */ + result = Curl_urldecode(data, data->state.path, 0, &path, NULL, TRUE); + if(result) + return result; + + /* Parse the path for the share */ + req->share = strdup((*path == '/' || *path == '\\') ? path + 1 : path); + if(!req->share) { + free(path); + + return CURLE_OUT_OF_MEMORY; + } + + slash = strchr(req->share, '/'); + if(!slash) + slash = strchr(req->share, '\\'); + + /* The share must be present */ + if(!slash) { + free(path); + + return CURLE_URL_MALFORMAT; + } + + /* Parse the path for the file path converting any forward slashes into + backslashes */ + *slash++ = 0; + req->path = slash; + for(; *slash; slash++) { + if(*slash == '/') + *slash = '\\'; + } + + free(path); + + return CURLE_OK; +} + +#endif /* !USE_WINDOWS_SSPI || USE_WIN32_CRYPTO */ + +#endif /* CURL_DISABLE_SMB && USE_NTLM && CURL_SIZEOF_CURL_OFF_T > 4 */ diff --git a/Utilities/cmcurl/lib/smb.h b/Utilities/cmcurl/lib/smb.h new file mode 100644 index 0000000..7852fa1 --- /dev/null +++ b/Utilities/cmcurl/lib/smb.h @@ -0,0 +1,271 @@ +#ifndef HEADER_CURL_SMB_H +#define HEADER_CURL_SMB_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2014, Bill Nagel <wnagel@tycoint.com>, Exacq Technologies + * + * 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 http://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. + * + ***************************************************************************/ + +enum smb_conn_state { + SMB_NOT_CONNECTED = 0, + SMB_CONNECTING, + SMB_NEGOTIATE, + SMB_SETUP, + SMB_CONNECTED +}; + +struct smb_conn { + enum smb_conn_state state; + char *user; + char *domain; + unsigned char challenge[8]; + unsigned int session_key; + unsigned short uid; + char *recv_buf; + size_t upload_size; + size_t send_size; + size_t sent; + size_t got; +}; + +/* + * Definitions for SMB protocol data structures + */ +#ifdef BUILDING_CURL_SMB_C + +#if defined(_MSC_VER) || defined(__ILEC400__) +# define PACK +# pragma pack(push) +# pragma pack(1) +#elif defined(__GNUC__) +# define PACK __attribute__((packed)) +#else +# define PACK +#endif + +#define SMB_COM_CLOSE 0x04 +#define SMB_COM_READ_ANDX 0x2e +#define SMB_COM_WRITE_ANDX 0x2f +#define SMB_COM_TREE_DISCONNECT 0x71 +#define SMB_COM_NEGOTIATE 0x72 +#define SMB_COM_SETUP_ANDX 0x73 +#define SMB_COM_TREE_CONNECT_ANDX 0x75 +#define SMB_COM_NT_CREATE_ANDX 0xa2 +#define SMB_COM_NO_ANDX_COMMAND 0xff + +#define SMB_WC_CLOSE 0x03 +#define SMB_WC_READ_ANDX 0x0c +#define SMB_WC_WRITE_ANDX 0x0e +#define SMB_WC_SETUP_ANDX 0x0d +#define SMB_WC_TREE_CONNECT_ANDX 0x04 +#define SMB_WC_NT_CREATE_ANDX 0x18 + +#define SMB_FLAGS_CANONICAL_PATHNAMES 0x10 +#define SMB_FLAGS_CASELESS_PATHNAMES 0x08 +#define SMB_FLAGS2_UNICODE_STRINGS 0x8000 +#define SMB_FLAGS2_IS_LONG_NAME 0x0040 +#define SMB_FLAGS2_KNOWS_LONG_NAME 0x0001 + +#define SMB_CAP_LARGE_FILES 0x08 +#define SMB_GENERIC_WRITE 0x40000000 +#define SMB_GENERIC_READ 0x80000000 +#define SMB_FILE_SHARE_ALL 0x07 +#define SMB_FILE_OPEN 0x01 +#define SMB_FILE_OVERWRITE_IF 0x05 + +#define SMB_ERR_NOACCESS 0x00050001 + +struct smb_header { + unsigned char nbt_type; + unsigned char nbt_flags; + unsigned short nbt_length; + unsigned char magic[4]; + unsigned char command; + unsigned int status; + unsigned char flags; + unsigned short flags2; + unsigned short pid_high; + unsigned char signature[8]; + unsigned short pad; + unsigned short tid; + unsigned short pid; + unsigned short uid; + unsigned short mid; +} PACK; + +struct smb_negotiate_response { + struct smb_header h; + unsigned char word_count; + unsigned short dialect_index; + unsigned char security_mode; + unsigned short max_mpx_count; + unsigned short max_number_vcs; + unsigned int max_buffer_size; + unsigned int max_raw_size; + unsigned int session_key; + unsigned int capabilities; + unsigned int system_time_low; + unsigned int system_time_high; + unsigned short server_time_zone; + unsigned char encryption_key_length; + unsigned short byte_count; + char bytes[1]; +} PACK; + +struct andx { + unsigned char command; + unsigned char pad; + unsigned short offset; +} PACK; + +struct smb_setup { + unsigned char word_count; + struct andx andx; + unsigned short max_buffer_size; + unsigned short max_mpx_count; + unsigned short vc_number; + unsigned int session_key; + unsigned short lengths[2]; + unsigned int pad; + unsigned int capabilities; + unsigned short byte_count; + char bytes[1024]; +} PACK; + +struct smb_tree_connect { + unsigned char word_count; + struct andx andx; + unsigned short flags; + unsigned short pw_len; + unsigned short byte_count; + char bytes[1024]; +} PACK; + +struct smb_nt_create { + unsigned char word_count; + struct andx andx; + unsigned char pad; + unsigned short name_length; + unsigned int flags; + unsigned int root_fid; + unsigned int access; +#ifdef HAVE_LONGLONG + unsigned long long allocation_size; +#else + unsigned __int64 allocation_size; +#endif + unsigned int ext_file_attributes; + unsigned int share_access; + unsigned int create_disposition; + unsigned int create_options; + unsigned int impersonation_level; + unsigned char security_flags; + unsigned short byte_count; + char bytes[1024]; +} PACK; + +struct smb_nt_create_response { + struct smb_header h; + unsigned char word_count; + struct andx andx; + unsigned char op_lock_level; + unsigned short fid; + unsigned int create_disposition; +#ifdef HAVE_LONGLONG + unsigned long long create_time; + unsigned long long last_access_time; + unsigned long long last_write_time; + unsigned long long last_change_time; +#else + unsigned __int64 create_time; + unsigned __int64 last_access_time; + unsigned __int64 last_write_time; + unsigned __int64 last_change_time; +#endif + unsigned int ext_file_attributes; +#ifdef HAVE_LONGLONG + unsigned long long allocation_size; + unsigned long long end_of_file; +#else + unsigned __int64 allocation_size; + unsigned __int64 end_of_file; +#endif +} PACK; + +struct smb_read { + unsigned char word_count; + struct andx andx; + unsigned short fid; + unsigned int offset; + unsigned short max_bytes; + unsigned short min_bytes; + unsigned int timeout; + unsigned short remaining; + unsigned int offset_high; + unsigned short byte_count; +} PACK; + +struct smb_write { + struct smb_header h; + unsigned char word_count; + struct andx andx; + unsigned short fid; + unsigned int offset; + unsigned int timeout; + unsigned short write_mode; + unsigned short remaining; + unsigned short pad; + unsigned short data_length; + unsigned short data_offset; + unsigned int offset_high; + unsigned short byte_count; + unsigned char pad2; +} PACK; + +struct smb_close { + unsigned char word_count; + unsigned short fid; + unsigned int last_mtime; + unsigned short byte_count; +} PACK; + +struct smb_tree_disconnect { + unsigned char word_count; + unsigned short byte_count; +} PACK; + +#if defined(_MSC_VER) || defined(__ILEC400__) +# pragma pack(pop) +#endif + +#endif /* BUILDING_CURL_SMB_C */ + +#if !defined(CURL_DISABLE_SMB) && defined(USE_NTLM) && \ + (CURL_SIZEOF_CURL_OFF_T > 4) + +#if !defined(USE_WINDOWS_SSPI) || defined(USE_WIN32_CRYPTO) + +extern const struct Curl_handler Curl_handler_smb; +extern const struct Curl_handler Curl_handler_smbs; + +#endif /* !USE_WINDOWS_SSPI || USE_WIN32_CRYPTO */ + +#endif /* CURL_DISABLE_SMB && USE_NTLM && CURL_SIZEOF_CURL_OFF_T > 4 */ + +#endif /* HEADER_CURL_SMB_H */ diff --git a/Utilities/cmcurl/lib/smtp.c b/Utilities/cmcurl/lib/smtp.c index 9aa8b15..dada087 100644 --- a/Utilities/cmcurl/lib/smtp.c +++ b/Utilities/cmcurl/lib/smtp.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -62,7 +62,6 @@ #include <curl/curl.h> #include "urldata.h" #include "sendf.h" -#include "if2ip.h" #include "hostip.h" #include "progress.h" #include "transfer.h" @@ -83,10 +82,7 @@ #include "curl_gethostname.h" #include "curl_sasl.h" #include "warnless.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - +#include "curl_printf.h" #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" @@ -106,10 +102,10 @@ static CURLcode smtp_setup_connection(struct connectdata *conn); static CURLcode smtp_parse_url_options(struct connectdata *conn); static CURLcode smtp_parse_url_path(struct connectdata *conn); static CURLcode smtp_parse_custom_request(struct connectdata *conn); -static CURLcode smtp_calc_sasl_details(struct connectdata *conn, - const char **mech, - char **initresp, size_t *len, - smtpstate *state1, smtpstate *state2); +static CURLcode smtp_perform_auth(struct connectdata *conn, const char *mech, + const char *initresp); +static CURLcode smtp_continue_auth(struct connectdata *conn, const char *resp); +static void smtp_get_message(char *buffer, char** outptr); /* * SMTP protocol handler. @@ -214,6 +210,17 @@ static const struct Curl_handler Curl_handler_smtps_proxy = { #endif #endif +/* SASL parameters for the smtp protocol */ +static const struct SASLproto saslsmtp = { + "smtp", /* The service name */ + 334, /* Code received when continuation is expected */ + 235, /* Code to receive upon authentication success */ + 512 - 8, /* Maximum initial response length (no max) */ + smtp_perform_auth, /* Send authentication command */ + smtp_continue_auth, /* Send authentication continuation */ + smtp_get_message /* Get SASL response message */ +}; + #ifdef USE_SSL static void smtp_to_smtps(struct connectdata *conn) { @@ -310,20 +317,7 @@ static void state(struct connectdata *conn, smtpstate newstate) "HELO", "STARTTLS", "UPGRADETLS", - "AUTH_PLAIN", - "AUTH_LOGIN", - "AUTH_LOGIN_PASSWD", - "AUTH_CRAMMD5", - "AUTH_DIGESTMD5", - "AUTH_DIGESTMD5_RESP", - "AUTH_NTLM", - "AUTH_NTLM_TYPE2MSG", - "AUTH_GSSAPI", - "AUTH_GSSAPI_TOKEN", - "AUTH_GSSAPI_NO_DATA", - "AUTH_XOAUTH2", - "AUTH_CANCEL", - "AUTH_FINAL", + "AUTH", "COMMAND", "MAIL", "RCPT", @@ -353,11 +347,11 @@ static CURLcode smtp_perform_ehlo(struct connectdata *conn) CURLcode result = CURLE_OK; struct smtp_conn *smtpc = &conn->proto.smtpc; - smtpc->authmechs = 0; /* No known authentication mechanisms yet */ - smtpc->authused = 0; /* Clear the authentication mechanism used - for esmtp connections */ - smtpc->tls_supported = FALSE; /* Clear the TLS capability */ - smtpc->auth_supported = FALSE; /* Clear the AUTH capability */ + smtpc->sasl.authmechs = SASL_AUTH_NONE; /* No known auth. mechanism yet */ + smtpc->sasl.authused = SASL_AUTH_NONE; /* Clear the authentication mechanism + used for esmtp connections */ + smtpc->tls_supported = FALSE; /* Clear the TLS capability */ + smtpc->auth_supported = FALSE; /* Clear the AUTH capability */ /* Send the EHLO command */ result = Curl_pp_sendf(&smtpc->pp, "EHLO %s", smtpc->domain); @@ -379,8 +373,8 @@ static CURLcode smtp_perform_helo(struct connectdata *conn) CURLcode result = CURLE_OK; struct smtp_conn *smtpc = &conn->proto.smtpc; - smtpc->authused = 0; /* No authentication mechanism used in smtp - connections */ + smtpc->sasl.authused = SASL_AUTH_NONE; /* No authentication mechanism used + in smtp connections */ /* Send the HELO command */ result = Curl_pp_sendf(&smtpc->pp, "HELO %s", smtpc->domain); @@ -446,25 +440,18 @@ static CURLcode smtp_perform_upgrade_tls(struct connectdata *conn) */ static CURLcode smtp_perform_auth(struct connectdata *conn, const char *mech, - const char *initresp, size_t len, - smtpstate state1, smtpstate state2) + const char *initresp) { CURLcode result = CURLE_OK; struct smtp_conn *smtpc = &conn->proto.smtpc; - if(initresp && 8 + strlen(mech) + len <= 512) { /* AUTH <mech> ...<crlf> */ + if(initresp) { /* AUTH <mech> ...<crlf> */ /* Send the AUTH command with the initial response */ result = Curl_pp_sendf(&smtpc->pp, "AUTH %s %s", mech, initresp); - - if(!result) - state(conn, state2); } else { /* Send the AUTH command */ result = Curl_pp_sendf(&smtpc->pp, "AUTH %s", mech); - - if(!result) - state(conn, state1); } return result; @@ -472,6 +459,19 @@ static CURLcode smtp_perform_auth(struct connectdata *conn, /*********************************************************************** * + * smtp_continue_auth() + * + * Sends SASL continuation data or cancellation. + */ +static CURLcode smtp_continue_auth(struct connectdata *conn, const char *resp) +{ + struct smtp_conn *smtpc = &conn->proto.smtpc; + + return Curl_pp_sendf(&smtpc->pp, "%s", resp); +} + +/*********************************************************************** + * * smtp_perform_authentication() * * Initiates the authentication sequence, with the appropriate SASL @@ -481,31 +481,22 @@ static CURLcode smtp_perform_authentication(struct connectdata *conn) { CURLcode result = CURLE_OK; struct smtp_conn *smtpc = &conn->proto.smtpc; - const char *mech = NULL; - char *initresp = NULL; - size_t len = 0; - smtpstate state1 = SMTP_STOP; - smtpstate state2 = SMTP_STOP; + saslprogress progress; - /* Check we have a username and password to authenticate with, and the + /* Check we have enough data to authenticate with, and the server supports authentiation, and end the connect phase if not */ - if(!conn->bits.user_passwd || !smtpc->auth_supported) { + if(!smtpc->auth_supported || + !Curl_sasl_can_authenticate(&smtpc->sasl, conn)) { state(conn, SMTP_STOP); - return result; } /* Calculate the SASL login details */ - result = smtp_calc_sasl_details(conn, &mech, &initresp, &len, &state1, - &state2); + result = Curl_sasl_start(&smtpc->sasl, conn, FALSE, &progress); if(!result) { - if(mech) { - /* Perform SASL based authentication */ - result = smtp_perform_auth(conn, mech, initresp, len, state1, state2); - - Curl_safefree(initresp); - } + if(progress == SASL_INPROGRESS) + state(conn, SMTP_AUTH); else { /* Other mechanisms not supported */ infof(conn->data, "No known authentication mechanisms supported!\n"); @@ -572,7 +563,7 @@ static CURLcode smtp_perform_mail(struct connectdata *conn) return CURLE_OUT_OF_MEMORY; /* Calculate the optional AUTH parameter */ - if(data->set.str[STRING_MAIL_AUTH] && conn->proto.smtpc.authused) { + if(data->set.str[STRING_MAIL_AUTH] && conn->proto.smtpc.sasl.authused) { if(data->set.str[STRING_MAIL_AUTH][0] != '\0') auth = aprintf("%s", data->set.str[STRING_MAIL_AUTH]); else @@ -580,7 +571,7 @@ static CURLcode smtp_perform_mail(struct connectdata *conn) auth = strdup("<>"); if(!auth) { - Curl_safefree(from); + free(from); return CURLE_OUT_OF_MEMORY; } @@ -591,8 +582,8 @@ static CURLcode smtp_perform_mail(struct connectdata *conn) size = aprintf("%" CURL_FORMAT_CURL_OFF_T, data->state.infilesize); if(!size) { - Curl_safefree(from); - Curl_safefree(auth); + free(from); + free(auth); return CURLE_OUT_OF_MEMORY; } @@ -612,9 +603,9 @@ static CURLcode smtp_perform_mail(struct connectdata *conn) result = Curl_pp_sendf(&conn->proto.smtpc.pp, "MAIL FROM:%s SIZE=%s", from, size); - Curl_safefree(from); - Curl_safefree(auth); - Curl_safefree(size); + free(from); + free(auth); + free(size); if(!result) state(conn, SMTP_MAIL); @@ -754,6 +745,9 @@ static CURLcode smtp_state_ehlo_resp(struct connectdata *conn, int smtpcode, /* Loop through the data line */ for(;;) { + size_t llen; + unsigned int mechbit; + while(len && (*line == ' ' || *line == '\t' || *line == '\r' || *line == '\n')) { @@ -772,22 +766,9 @@ static CURLcode smtp_state_ehlo_resp(struct connectdata *conn, int smtpcode, wordlen++; /* Test the word for a matching authentication mechanism */ - if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_LOGIN)) - smtpc->authmechs |= SASL_MECH_LOGIN; - else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_PLAIN)) - smtpc->authmechs |= SASL_MECH_PLAIN; - else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_CRAM_MD5)) - smtpc->authmechs |= SASL_MECH_CRAM_MD5; - else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_DIGEST_MD5)) - smtpc->authmechs |= SASL_MECH_DIGEST_MD5; - else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_GSSAPI)) - smtpc->authmechs |= SASL_MECH_GSSAPI; - else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_EXTERNAL)) - smtpc->authmechs |= SASL_MECH_EXTERNAL; - else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_NTLM)) - smtpc->authmechs |= SASL_MECH_NTLM; - else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_XOAUTH2)) - smtpc->authmechs |= SASL_MECH_XOAUTH2; + if((mechbit = Curl_sasl_decode_mech(line, wordlen, &llen)) && + llen == wordlen) + smtpc->sasl.authmechs |= mechbit; line += wordlen; len -= wordlen; @@ -836,565 +817,31 @@ static CURLcode smtp_state_helo_resp(struct connectdata *conn, int smtpcode, return result; } -/* For AUTH PLAIN (without initial response) responses */ -static CURLcode smtp_state_auth_plain_resp(struct connectdata *conn, - int smtpcode, - smtpstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - size_t len = 0; - char *plainauth = NULL; - - (void)instate; /* no use for this yet */ - - if(smtpcode != 334) { - failf(data, "Access denied: %d", smtpcode); - result = CURLE_LOGIN_DENIED; - } - else { - /* Create the authorisation message */ - result = Curl_sasl_create_plain_message(conn->data, conn->user, - conn->passwd, &plainauth, &len); - if(!result && plainauth) { - /* Send the message */ - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", plainauth); - - if(!result) - state(conn, SMTP_AUTH_FINAL); - } - } - - Curl_safefree(plainauth); - - return result; -} - -/* For AUTH LOGIN (without initial response) responses */ -static CURLcode smtp_state_auth_login_resp(struct connectdata *conn, - int smtpcode, - smtpstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - size_t len = 0; - char *authuser = NULL; - - (void)instate; /* no use for this yet */ - - if(smtpcode != 334) { - failf(data, "Access denied: %d", smtpcode); - result = CURLE_LOGIN_DENIED; - } - else { - /* Create the user message */ - result = Curl_sasl_create_login_message(conn->data, conn->user, - &authuser, &len); - if(!result && authuser) { - /* Send the user */ - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", authuser); - - if(!result) - state(conn, SMTP_AUTH_LOGIN_PASSWD); - } - } - - Curl_safefree(authuser); - - return result; -} - -/* For AUTH LOGIN user entry responses */ -static CURLcode smtp_state_auth_login_password_resp(struct connectdata *conn, - int smtpcode, - smtpstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - size_t len = 0; - char *authpasswd = NULL; - - (void)instate; /* no use for this yet */ - - if(smtpcode != 334) { - failf(data, "Access denied: %d", smtpcode); - result = CURLE_LOGIN_DENIED; - } - else { - /* Create the password message */ - result = Curl_sasl_create_login_message(conn->data, conn->passwd, - &authpasswd, &len); - if(!result && authpasswd) { - /* Send the password */ - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", authpasswd); - - if(!result) - state(conn, SMTP_AUTH_FINAL); - } - } - - Curl_safefree(authpasswd); - - return result; -} - -#ifndef CURL_DISABLE_CRYPTO_AUTH -/* For AUTH CRAM-MD5 responses */ -static CURLcode smtp_state_auth_cram_resp(struct connectdata *conn, - int smtpcode, - smtpstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - char *chlg = NULL; - char *chlg64 = NULL; - char *rplyb64 = NULL; - size_t len = 0; - - (void)instate; /* no use for this yet */ - - if(smtpcode != 334) { - failf(data, "Access denied: %d", smtpcode); - return CURLE_LOGIN_DENIED; - } - - /* Get the challenge message */ - smtp_get_message(data->state.buffer, &chlg64); - - /* Decode the challenge message */ - result = Curl_sasl_decode_cram_md5_message(chlg64, &chlg, &len); - if(result) { - /* Send the cancellation */ - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "*"); - - if(!result) - state(conn, SMTP_AUTH_CANCEL); - } - else { - /* Create the response message */ - result = Curl_sasl_create_cram_md5_message(data, chlg, conn->user, - conn->passwd, &rplyb64, &len); - if(!result && rplyb64) { - /* Send the response */ - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", rplyb64); - - if(!result) - state(conn, SMTP_AUTH_FINAL); - } - } - - Curl_safefree(chlg); - Curl_safefree(rplyb64); - - return result; -} - -/* For AUTH DIGEST-MD5 challenge responses */ -static CURLcode smtp_state_auth_digest_resp(struct connectdata *conn, - int smtpcode, - smtpstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - char *chlg64 = NULL; - char *rplyb64 = NULL; - size_t len = 0; - - (void)instate; /* no use for this yet */ - - if(smtpcode != 334) { - failf(data, "Access denied: %d", smtpcode); - return CURLE_LOGIN_DENIED; - } - - /* Get the challenge message */ - smtp_get_message(data->state.buffer, &chlg64); - - /* Create the response message */ - result = Curl_sasl_create_digest_md5_message(data, chlg64, - conn->user, conn->passwd, - "smtp", &rplyb64, &len); - if(result) { - if(result == CURLE_BAD_CONTENT_ENCODING) { - /* Send the cancellation */ - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "*"); - - if(!result) - state(conn, SMTP_AUTH_CANCEL); - } - } - else { - /* Send the response */ - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", rplyb64); - - if(!result) - state(conn, SMTP_AUTH_DIGESTMD5_RESP); - } - - Curl_safefree(rplyb64); - - return result; -} - -/* For AUTH DIGEST-MD5 challenge-response responses */ -static CURLcode smtp_state_auth_digest_resp_resp(struct connectdata *conn, - int smtpcode, - smtpstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - - (void)instate; /* no use for this yet */ - - if(smtpcode != 334) { - failf(data, "Authentication failed: %d", smtpcode); - result = CURLE_LOGIN_DENIED; - } - else { - /* Send an empty response */ - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", ""); - - if(!result) - state(conn, SMTP_AUTH_FINAL); - } - - return result; -} - -#endif - -#ifdef USE_NTLM -/* For AUTH NTLM (without initial response) responses */ -static CURLcode smtp_state_auth_ntlm_resp(struct connectdata *conn, - int smtpcode, - smtpstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - char *type1msg = NULL; - size_t len = 0; - - (void)instate; /* no use for this yet */ - - if(smtpcode != 334) { - failf(data, "Access denied: %d", smtpcode); - result = CURLE_LOGIN_DENIED; - } - else { - /* Create the type-1 message */ - result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd, - &conn->ntlm, - &type1msg, &len); - if(!result && type1msg) { - /* Send the message */ - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", type1msg); - - if(!result) - state(conn, SMTP_AUTH_NTLM_TYPE2MSG); - } - } - - Curl_safefree(type1msg); - - return result; -} - -/* For NTLM type-2 responses (sent in reponse to our type-1 message) */ -static CURLcode smtp_state_auth_ntlm_type2msg_resp(struct connectdata *conn, - int smtpcode, - smtpstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - char *type2msg = NULL; - char *type3msg = NULL; - size_t len = 0; - - (void)instate; /* no use for this yet */ - - if(smtpcode != 334) { - failf(data, "Access denied: %d", smtpcode); - result = CURLE_LOGIN_DENIED; - } - else { - /* Get the type-2 message */ - smtp_get_message(data->state.buffer, &type2msg); - - /* Decode the type-2 message */ - result = Curl_sasl_decode_ntlm_type2_message(data, type2msg, &conn->ntlm); - if(result) { - /* Send the cancellation */ - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "*"); - - if(!result) - state(conn, SMTP_AUTH_CANCEL); - } - else { - /* Create the type-3 message */ - result = Curl_sasl_create_ntlm_type3_message(data, conn->user, - conn->passwd, &conn->ntlm, - &type3msg, &len); - if(!result && type3msg) { - /* Send the message */ - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", type3msg); - - if(!result) - state(conn, SMTP_AUTH_FINAL); - } - } - } - - Curl_safefree(type3msg); - - return result; -} -#endif - -#if defined(USE_WINDOWS_SSPI) -/* For AUTH GSSAPI (without initial response) responses */ -static CURLcode smtp_state_auth_gssapi_resp(struct connectdata *conn, - int smtpcode, - smtpstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - struct smtp_conn *smtpc = &conn->proto.smtpc; - char *respmsg = NULL; - size_t len = 0; - - (void)instate; /* no use for this yet */ - - if(smtpcode != 334) { - failf(data, "Access denied: %d", smtpcode); - result = CURLE_LOGIN_DENIED; - } - else { - /* Create the initial response message */ - result = Curl_sasl_create_gssapi_user_message(data, conn->user, - conn->passwd, "smtp", - smtpc->mutual_auth, NULL, - &conn->krb5, - &respmsg, &len); - if(!result && respmsg) { - /* Send the message */ - result = Curl_pp_sendf(&smtpc->pp, "%s", respmsg); - - if(!result) - state(conn, SMTP_AUTH_GSSAPI_TOKEN); - } - } - - Curl_safefree(respmsg); - - return result; -} - -/* For AUTH GSSAPI user token responses */ -static CURLcode smtp_state_auth_gssapi_token_resp(struct connectdata *conn, - int smtpcode, - smtpstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - struct smtp_conn *smtpc = &conn->proto.smtpc; - char *chlgmsg = NULL; - char *respmsg = NULL; - size_t len = 0; - - (void)instate; /* no use for this yet */ - - if(smtpcode != 334) { - failf(data, "Access denied: %d", smtpcode); - result = CURLE_LOGIN_DENIED; - } - else { - /* Get the challenge message */ - smtp_get_message(data->state.buffer, &chlgmsg); - - if(smtpc->mutual_auth) - /* Decode the user token challenge and create the optional response - message */ - result = Curl_sasl_create_gssapi_user_message(data, NULL, NULL, NULL, - smtpc->mutual_auth, - chlgmsg, &conn->krb5, - &respmsg, &len); - else - /* Decode the security challenge and create the response message */ - result = Curl_sasl_create_gssapi_security_message(data, chlgmsg, - &conn->krb5, - &respmsg, &len); - - if(result) { - if(result == CURLE_BAD_CONTENT_ENCODING) { - /* Send the cancellation */ - result = Curl_pp_sendf(&smtpc->pp, "%s", "*"); - - if(!result) - state(conn, SMTP_AUTH_CANCEL); - } - } - else { - /* Send the response */ - if(respmsg) - result = Curl_pp_sendf(&smtpc->pp, "%s", respmsg); - else - result = Curl_pp_sendf(&smtpc->pp, "%s", ""); - - if(!result) - state(conn, (smtpc->mutual_auth ? SMTP_AUTH_GSSAPI_NO_DATA : - SMTP_AUTH_FINAL)); - } - } - - Curl_safefree(respmsg); - - return result; -} - -/* For AUTH GSSAPI no data responses */ -static CURLcode smtp_state_auth_gssapi_no_data_resp(struct connectdata *conn, - int smtpcode, - smtpstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - char *chlgmsg = NULL; - char *respmsg = NULL; - size_t len = 0; - - (void)instate; /* no use for this yet */ - - if(smtpcode != 334) { - failf(data, "Access denied: %d", smtpcode); - result = CURLE_LOGIN_DENIED; - } - else { - /* Get the challenge message */ - smtp_get_message(data->state.buffer, &chlgmsg); - - /* Decode the security challenge and create the response message */ - result = Curl_sasl_create_gssapi_security_message(data, chlgmsg, - &conn->krb5, - &respmsg, &len); - if(result) { - if(result == CURLE_BAD_CONTENT_ENCODING) { - /* Send the cancellation */ - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "*"); - - if(!result) - state(conn, SMTP_AUTH_CANCEL); - } - } - else { - /* Send the response */ - if(respmsg) { - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", respmsg); - - if(!result) - state(conn, SMTP_AUTH_FINAL); - } - } - } - - Curl_safefree(respmsg); - - return result; -} -#endif - -/* For AUTH XOAUTH2 (without initial response) responses */ -static CURLcode smtp_state_auth_xoauth2_resp(struct connectdata *conn, - int smtpcode, smtpstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - size_t len = 0; - char *xoauth = NULL; - - (void)instate; /* no use for this yet */ - - if(smtpcode != 334) { - failf(data, "Access denied: %d", smtpcode); - result = CURLE_LOGIN_DENIED; - } - else { - /* Create the authorisation message */ - result = Curl_sasl_create_xoauth2_message(conn->data, conn->user, - conn->xoauth2_bearer, - &xoauth, &len); - if(!result && xoauth) { - /* Send the message */ - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", xoauth); - - if(!result) - state(conn, SMTP_AUTH_FINAL); - } - } - - Curl_safefree(xoauth); - - return result; -} - -/* For AUTH cancellation responses */ -static CURLcode smtp_state_auth_cancel_resp(struct connectdata *conn, - int smtpcode, - smtpstate instate) +/* For SASL authentication responses */ +static CURLcode smtp_state_auth_resp(struct connectdata *conn, + int smtpcode, + smtpstate instate) { CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; struct smtp_conn *smtpc = &conn->proto.smtpc; - const char *mech = NULL; - char *initresp = NULL; - size_t len = 0; - smtpstate state1 = SMTP_STOP; - smtpstate state2 = SMTP_STOP; + saslprogress progress; - (void)smtpcode; (void)instate; /* no use for this yet */ - /* Remove the offending mechanism from the supported list */ - smtpc->authmechs ^= smtpc->authused; - - /* Calculate alternative SASL login details */ - result = smtp_calc_sasl_details(conn, &mech, &initresp, &len, &state1, - &state2); - - if(!result) { - /* Do we have any mechanisms left? */ - if(mech) { - /* Retry SASL based authentication */ - result = smtp_perform_auth(conn, mech, initresp, len, state1, state2); - - Curl_safefree(initresp); - } - else { + result = Curl_sasl_continue(&smtpc->sasl, conn, smtpcode, &progress); + if(!result) + switch(progress) { + case SASL_DONE: + state(conn, SMTP_STOP); /* Authenticated */ + break; + case SASL_IDLE: /* No mechanism left after cancellation */ failf(data, "Authentication cancelled"); - result = CURLE_LOGIN_DENIED; + break; + default: + break; } - } - - return result; -} - -/* For final responses in the AUTH sequence */ -static CURLcode smtp_state_auth_final_resp(struct connectdata *conn, - int smtpcode, - smtpstate instate) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - - (void)instate; /* no use for this yet */ - - if(smtpcode != 235) { - failf(data, "Authentication failed: %d", smtpcode); - result = CURLE_LOGIN_DENIED; - } - else - /* End of connect phase */ - state(conn, SMTP_STOP); return result; } @@ -1592,69 +1039,8 @@ static CURLcode smtp_statemach_act(struct connectdata *conn) result = smtp_state_starttls_resp(conn, smtpcode, smtpc->state); break; - case SMTP_AUTH_PLAIN: - result = smtp_state_auth_plain_resp(conn, smtpcode, smtpc->state); - break; - - case SMTP_AUTH_LOGIN: - result = smtp_state_auth_login_resp(conn, smtpcode, smtpc->state); - break; - - case SMTP_AUTH_LOGIN_PASSWD: - result = smtp_state_auth_login_password_resp(conn, smtpcode, - smtpc->state); - break; - -#ifndef CURL_DISABLE_CRYPTO_AUTH - case SMTP_AUTH_CRAMMD5: - result = smtp_state_auth_cram_resp(conn, smtpcode, smtpc->state); - break; - - case SMTP_AUTH_DIGESTMD5: - result = smtp_state_auth_digest_resp(conn, smtpcode, smtpc->state); - break; - - case SMTP_AUTH_DIGESTMD5_RESP: - result = smtp_state_auth_digest_resp_resp(conn, smtpcode, smtpc->state); - break; -#endif - -#ifdef USE_NTLM - case SMTP_AUTH_NTLM: - result = smtp_state_auth_ntlm_resp(conn, smtpcode, smtpc->state); - break; - - case SMTP_AUTH_NTLM_TYPE2MSG: - result = smtp_state_auth_ntlm_type2msg_resp(conn, smtpcode, - smtpc->state); - break; -#endif - -#if defined(USE_WINDOWS_SSPI) - case SMTP_AUTH_GSSAPI: - result = smtp_state_auth_gssapi_resp(conn, smtpcode, smtpc->state); - break; - - case SMTP_AUTH_GSSAPI_TOKEN: - result = smtp_state_auth_gssapi_token_resp(conn, smtpcode, smtpc->state); - break; - - case SMTP_AUTH_GSSAPI_NO_DATA: - result = smtp_state_auth_gssapi_no_data_resp(conn, smtpcode, - smtpc->state); - break; -#endif - - case SMTP_AUTH_XOAUTH2: - result = smtp_state_auth_xoauth2_resp(conn, smtpcode, smtpc->state); - break; - - case SMTP_AUTH_CANCEL: - result = smtp_state_auth_cancel_resp(conn, smtpcode, smtpc->state); - break; - - case SMTP_AUTH_FINAL: - result = smtp_state_auth_final_resp(conn, smtpcode, smtpc->state); + case SMTP_AUTH: + result = smtp_state_auth_resp(conn, smtpcode, smtpc->state); break; case SMTP_COMMAND: @@ -1767,8 +1153,8 @@ static CURLcode smtp_connect(struct connectdata *conn, bool *done) pp->endofresp = smtp_endofresp; pp->conn = conn; - /* Set the default preferred authentication mechanism */ - smtpc->prefmech = SASL_AUTH_ANY; + /* Initialize the SASL storage */ + Curl_sasl_init(&smtpc->sasl, &saslsmtp); /* Initialise the pingpong layer */ Curl_pp_init(pp); @@ -1807,7 +1193,7 @@ static CURLcode smtp_done(struct connectdata *conn, CURLcode status, struct SessionHandle *data = conn->data; struct SMTP *smtp = data->req.protop; struct pingpong *pp = &conn->proto.smtpc.pp; - const char *eob; + char *eob; ssize_t len; ssize_t bytes_written; @@ -1827,30 +1213,45 @@ static CURLcode smtp_done(struct connectdata *conn, CURLcode status, else if(!data->set.connect_only && data->set.upload && data->set.mail_rcpt) { /* 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. */ - eob = SMTP_EOB; - len = SMTP_EOB_LEN; + is "no mail data". RFC-5321, sect. 4.1.1.4. + + Note: As some SSL backends, such as OpenSSL, will cause Curl_write() to + fail when using a different pointer following a previous write, that + returned CURLE_AGAIN, we duplicate the EOB now rather than when the + bytes written doesn't equal len. */ if(smtp->trailing_crlf || !conn->data->state.infilesize) { - eob += 2; - len -= 2; + eob = strdup(SMTP_EOB + 2); + len = SMTP_EOB_LEN - 2; + } + else { + eob = strdup(SMTP_EOB); + len = SMTP_EOB_LEN; } + if(!eob) + return CURLE_OUT_OF_MEMORY; + /* Send the end of block data */ result = Curl_write(conn, conn->writesockfd, eob, len, &bytes_written); - if(result) + if(result) { + free(eob); return result; + } if(bytes_written != len) { /* The whole chunk was not sent so keep it around and adjust the pingpong structure accordingly */ - pp->sendthis = strdup(eob); + pp->sendthis = eob; pp->sendsize = len; pp->sendleft = len - bytes_written; } - else + else { /* Successfully sent so adjust the response timeout relative to now */ pp->response = Curl_tvnow(); + free(eob); + } + state(conn, SMTP_POSTDATA); /* Run the state-machine @@ -1971,7 +1372,7 @@ static CURLcode smtp_disconnect(struct connectdata *conn, bool dead_connection) Curl_pp_disconnect(&smtpc->pp); /* Cleanup the SASL module */ - Curl_sasl_cleanup(conn, smtpc->authused); + Curl_sasl_cleanup(conn, smtpc->sasl.authused); /* Cleanup our connection based variables */ Curl_safefree(smtpc->domain); @@ -2092,52 +1493,30 @@ static CURLcode smtp_parse_url_options(struct connectdata *conn) { CURLcode result = CURLE_OK; struct smtp_conn *smtpc = &conn->proto.smtpc; - const char *options = conn->options; - const char *ptr = options; - bool reset = TRUE; + const char *ptr = conn->options; - while(ptr && *ptr) { + smtpc->sasl.resetprefs = TRUE; + + while(!result && ptr && *ptr) { const char *key = ptr; + const char *value; while(*ptr && *ptr != '=') ptr++; - if(strnequal(key, "AUTH", 4)) { - size_t len = 0; - const char *value = ++ptr; - - if(reset) { - reset = FALSE; - smtpc->prefmech = SASL_AUTH_NONE; - } + value = ptr + 1; - while(*ptr && *ptr != ';') { - ptr++; - len++; - } + while(*ptr && *ptr != ';') + ptr++; - if(strnequal(value, "*", len)) - smtpc->prefmech = SASL_AUTH_ANY; - else if(strnequal(value, SASL_MECH_STRING_LOGIN, len)) - smtpc->prefmech |= SASL_MECH_LOGIN; - else if(strnequal(value, SASL_MECH_STRING_PLAIN, len)) - smtpc->prefmech |= SASL_MECH_PLAIN; - else if(strnequal(value, SASL_MECH_STRING_CRAM_MD5, len)) - smtpc->prefmech |= SASL_MECH_CRAM_MD5; - else if(strnequal(value, SASL_MECH_STRING_DIGEST_MD5, len)) - smtpc->prefmech |= SASL_MECH_DIGEST_MD5; - else if(strnequal(value, SASL_MECH_STRING_GSSAPI, len)) - smtpc->prefmech |= SASL_MECH_GSSAPI; - else if(strnequal(value, SASL_MECH_STRING_NTLM, len)) - smtpc->prefmech |= SASL_MECH_NTLM; - else if(strnequal(value, SASL_MECH_STRING_XOAUTH2, len)) - smtpc->prefmech |= SASL_MECH_XOAUTH2; - - if(*ptr == ';') - ptr++; - } + if(strnequal(key, "AUTH=", 5)) + result = Curl_sasl_parse_url_auth_option(&smtpc->sasl, + value, ptr - value); else result = CURLE_URL_MALFORMAT; + + if(*ptr == ';') + ptr++; } return result; @@ -2189,111 +1568,7 @@ static CURLcode smtp_parse_custom_request(struct connectdata *conn) return result; } -/*********************************************************************** - * - * smtp_calc_sasl_details() - * - * Calculate the required login details for SASL authentication. - */ -static CURLcode smtp_calc_sasl_details(struct connectdata *conn, - const char **mech, - char **initresp, size_t *len, - smtpstate *state1, smtpstate *state2) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - struct smtp_conn *smtpc = &conn->proto.smtpc; - - /* Calculate the supported authentication mechanism, by decreasing order of - security, as well as the initial response where appropriate */ -#if defined(USE_WINDOWS_SSPI) - if((smtpc->authmechs & SASL_MECH_GSSAPI) && - (smtpc->prefmech & SASL_MECH_GSSAPI)) { - smtpc->mutual_auth = FALSE; /* TODO: Calculate mutual authentication */ - - *mech = SASL_MECH_STRING_GSSAPI; - *state1 = SMTP_AUTH_GSSAPI; - *state2 = SMTP_AUTH_GSSAPI_TOKEN; - smtpc->authused = SASL_MECH_GSSAPI; - - if(data->set.sasl_ir) - result = Curl_sasl_create_gssapi_user_message(data, conn->user, - conn->passwd, "smtp", - smtpc->mutual_auth, - NULL, &conn->krb5, - initresp, len); - } - else -#endif -#ifndef CURL_DISABLE_CRYPTO_AUTH - if((smtpc->authmechs & SASL_MECH_DIGEST_MD5) && - (smtpc->prefmech & SASL_MECH_DIGEST_MD5)) { - *mech = SASL_MECH_STRING_DIGEST_MD5; - *state1 = SMTP_AUTH_DIGESTMD5; - smtpc->authused = SASL_MECH_DIGEST_MD5; - } - else if((smtpc->authmechs & SASL_MECH_CRAM_MD5) && - (smtpc->prefmech & SASL_MECH_CRAM_MD5)) { - *mech = SASL_MECH_STRING_CRAM_MD5; - *state1 = SMTP_AUTH_CRAMMD5; - smtpc->authused = SASL_MECH_CRAM_MD5; - } - else -#endif -#ifdef USE_NTLM - if((smtpc->authmechs & SASL_MECH_NTLM) && - (smtpc->prefmech & SASL_MECH_NTLM)) { - *mech = SASL_MECH_STRING_NTLM; - *state1 = SMTP_AUTH_NTLM; - *state2 = SMTP_AUTH_NTLM_TYPE2MSG; - smtpc->authused = SASL_MECH_NTLM; - - if(data->set.sasl_ir) - result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd, - &conn->ntlm, - initresp, len); - } - else -#endif - if(((smtpc->authmechs & SASL_MECH_XOAUTH2) && - (smtpc->prefmech & SASL_MECH_XOAUTH2) && - (smtpc->prefmech != SASL_AUTH_ANY)) || conn->xoauth2_bearer) { - *mech = SASL_MECH_STRING_XOAUTH2; - *state1 = SMTP_AUTH_XOAUTH2; - *state2 = SMTP_AUTH_FINAL; - smtpc->authused = SASL_MECH_XOAUTH2; - - if(data->set.sasl_ir) - result = Curl_sasl_create_xoauth2_message(data, conn->user, - conn->xoauth2_bearer, - initresp, len); - } - else if((smtpc->authmechs & SASL_MECH_LOGIN) && - (smtpc->prefmech & SASL_MECH_LOGIN)) { - *mech = SASL_MECH_STRING_LOGIN; - *state1 = SMTP_AUTH_LOGIN; - *state2 = SMTP_AUTH_LOGIN_PASSWD; - smtpc->authused = SASL_MECH_LOGIN; - - if(data->set.sasl_ir) - result = Curl_sasl_create_login_message(data, conn->user, initresp, len); - } - else if((smtpc->authmechs & SASL_MECH_PLAIN) && - (smtpc->prefmech & SASL_MECH_PLAIN)) { - *mech = SASL_MECH_STRING_PLAIN; - *state1 = SMTP_AUTH_PLAIN; - *state2 = SMTP_AUTH_FINAL; - smtpc->authused = SASL_MECH_PLAIN; - - if(data->set.sasl_ir) - result = Curl_sasl_create_plain_message(data, conn->user, conn->passwd, - initresp, len); - } - - return result; -} - -CURLcode Curl_smtp_escape_eob(struct connectdata *conn, ssize_t nread) +CURLcode Curl_smtp_escape_eob(struct connectdata *conn, const ssize_t nread) { /* When sending a SMTP payload we must detect CRLF. sequences making sure they are sent as CRLF.. instead, as a . on the beginning of a line will @@ -2305,17 +1580,26 @@ CURLcode Curl_smtp_escape_eob(struct connectdata *conn, ssize_t nread) ssize_t si; struct SessionHandle *data = conn->data; struct SMTP *smtp = data->req.protop; + char *scratch = data->state.scratch; + char *newscratch = NULL; + char *oldscratch = NULL; + size_t eob_sent; + + /* Do we need to allocate a scratch buffer? */ + if(!scratch || data->set.crlf) { + oldscratch = scratch; - /* Do we need to allocate the scatch buffer? */ - if(!data->state.scratch) { - data->state.scratch = malloc(2 * BUFSIZE); + scratch = newscratch = malloc(2 * BUFSIZE); + if(!newscratch) { + failf(data, "Failed to alloc scratch buffer!"); - if(!data->state.scratch) { - failf (data, "Failed to alloc scratch buffer!"); return CURLE_OUT_OF_MEMORY; } } + /* Have we already sent part of the EOB? */ + eob_sent = smtp->eob; + /* This loop can be improved by some kind of Boyer-Moore style of approach but that is saved for later... */ for(i = 0, si = 0; i < nread; i++) { @@ -2330,8 +1614,8 @@ CURLcode Curl_smtp_escape_eob(struct connectdata *conn, ssize_t nread) } else if(smtp->eob) { /* A previous substring matched so output that first */ - memcpy(&data->state.scratch[si], SMTP_EOB, smtp->eob); - si += smtp->eob; + memcpy(&scratch[si], &SMTP_EOB[eob_sent], smtp->eob - eob_sent); + si += smtp->eob - eob_sent; /* Then compare the first byte */ if(SMTP_EOB[0] == data->req.upload_fromhere[i]) @@ -2339,6 +1623,8 @@ CURLcode Curl_smtp_escape_eob(struct connectdata *conn, ssize_t nread) else smtp->eob = 0; + eob_sent = 0; + /* Reset the trailing CRLF flag as there was more data */ smtp->trailing_crlf = FALSE; } @@ -2346,31 +1632,38 @@ CURLcode Curl_smtp_escape_eob(struct connectdata *conn, ssize_t nread) /* Do we have a match for CRLF. as per RFC-5321, sect. 4.5.2 */ if(SMTP_EOB_FIND_LEN == smtp->eob) { /* Copy the replacement data to the target buffer */ - memcpy(&data->state.scratch[si], SMTP_EOB_REPL, SMTP_EOB_REPL_LEN); - si += SMTP_EOB_REPL_LEN; + memcpy(&scratch[si], &SMTP_EOB_REPL[eob_sent], + SMTP_EOB_REPL_LEN - eob_sent); + si += SMTP_EOB_REPL_LEN - eob_sent; smtp->eob = 0; + eob_sent = 0; } else if(!smtp->eob) - data->state.scratch[si++] = data->req.upload_fromhere[i]; + scratch[si++] = data->req.upload_fromhere[i]; } - if(smtp->eob) { + if(smtp->eob - eob_sent) { /* A substring matched before processing ended so output that now */ - memcpy(&data->state.scratch[si], SMTP_EOB, smtp->eob); - si += smtp->eob; - smtp->eob = 0; + memcpy(&scratch[si], &SMTP_EOB[eob_sent], smtp->eob - eob_sent); + si += smtp->eob - eob_sent; } + /* Only use the new buffer if we replaced something */ if(si != nread) { - /* Only use the new buffer if we replaced something */ - nread = si; - /* Upload from the new (replaced) buffer instead */ - data->req.upload_fromhere = data->state.scratch; + data->req.upload_fromhere = scratch; + + /* Save the buffer so it can be freed later */ + data->state.scratch = scratch; + + /* Free the old scratch buffer */ + free(oldscratch); /* Set the new amount too */ - data->req.upload_present = nread; + data->req.upload_present = si; } + else + free(newscratch); return CURLE_OK; } diff --git a/Utilities/cmcurl/lib/smtp.h b/Utilities/cmcurl/lib/smtp.h index db1b1e6..9fbe0c5 100644 --- a/Utilities/cmcurl/lib/smtp.h +++ b/Utilities/cmcurl/lib/smtp.h @@ -23,6 +23,7 @@ ***************************************************************************/ #include "pingpong.h" +#include "curl_sasl.h" /**************************************************************************** * SMTP unique setup @@ -36,20 +37,7 @@ typedef enum { SMTP_STARTTLS, SMTP_UPGRADETLS, /* asynchronously upgrade the connection to SSL/TLS (multi mode only) */ - SMTP_AUTH_PLAIN, - SMTP_AUTH_LOGIN, - SMTP_AUTH_LOGIN_PASSWD, - SMTP_AUTH_CRAMMD5, - SMTP_AUTH_DIGESTMD5, - SMTP_AUTH_DIGESTMD5_RESP, - SMTP_AUTH_NTLM, - SMTP_AUTH_NTLM_TYPE2MSG, - SMTP_AUTH_GSSAPI, - SMTP_AUTH_GSSAPI_TOKEN, - SMTP_AUTH_GSSAPI_NO_DATA, - SMTP_AUTH_XOAUTH2, - SMTP_AUTH_CANCEL, - SMTP_AUTH_FINAL, + SMTP_AUTH, SMTP_COMMAND, /* VRFY, EXPN, NOOP, RSET and HELP */ SMTP_MAIL, /* MAIL FROM */ SMTP_RCPT, /* RCPT TO */ @@ -79,14 +67,11 @@ struct smtp_conn { smtpstate state; /* Always use smtp.c:state() to change state! */ bool ssldone; /* Is connect() over SSL done? */ char *domain; /* Client address/name to send in the EHLO */ - unsigned int authmechs; /* Accepted authentication mechanisms */ - unsigned int prefmech; /* Preferred authentication mechanism */ - unsigned int authused; /* Auth mechanism used for the connection */ + struct SASL sasl; /* SASL-related storage */ bool tls_supported; /* StartTLS capability supported by server */ bool size_supported; /* If server supports SIZE extension according to RFC 1870 */ bool auth_supported; /* AUTH capability supported by server */ - bool mutual_auth; /* Mutual authentication enabled (GSSAPI only) */ }; extern const struct Curl_handler Curl_handler_smtp; @@ -101,6 +86,6 @@ extern const struct Curl_handler Curl_handler_smtps; #define SMTP_EOB_REPL "\x0d\x0a\x2e\x2e" #define SMTP_EOB_REPL_LEN 4 -CURLcode Curl_smtp_escape_eob(struct connectdata *conn, ssize_t nread); +CURLcode Curl_smtp_escape_eob(struct connectdata *conn, const ssize_t nread); #endif /* HEADER_CURL_SMTP_H */ diff --git a/Utilities/cmcurl/lib/socks.c b/Utilities/cmcurl/lib/socks.c index 028475c..7d3f782 100644 --- a/Utilities/cmcurl/lib/socks.c +++ b/Utilities/cmcurl/lib/socks.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -127,7 +127,7 @@ CURLcode Curl_SOCKS4(const char *proxy_name, return CURLE_OPERATION_TIMEDOUT; } - curlx_nonblock(sock, FALSE); + (void)curlx_nonblock(sock, FALSE); infof(data, "SOCKS4 communication to %s:%d\n", hostname, remote_port); @@ -238,7 +238,7 @@ CURLcode Curl_SOCKS4(const char *proxy_name, code = Curl_write_plain(conn, sock, (char *)socksreq, packetsize + hostnamelen, &written); - if((code != CURLE_OK) || (written != packetsize + hostnamelen)) { + if(code || (written != packetsize + hostnamelen)) { failf(data, "Failed to send SOCKS4 connect request."); return CURLE_COULDNT_CONNECT; } @@ -247,7 +247,7 @@ CURLcode Curl_SOCKS4(const char *proxy_name, hostnamelen = (ssize_t)strlen(hostname) + 1; code = Curl_write_plain(conn, sock, (char *)hostname, hostnamelen, &written); - if((code != CURLE_OK) || (written != hostnamelen)) { + if(code || (written != hostnamelen)) { failf(data, "Failed to send SOCKS4 connect request."); return CURLE_COULDNT_CONNECT; } @@ -258,7 +258,7 @@ CURLcode Curl_SOCKS4(const char *proxy_name, /* Receive response */ result = Curl_blockread_all(conn, sock, (char *)socksreq, packetsize, &actualread); - if((result != CURLE_OK) || (actualread != packetsize)) { + if(result || (actualread != packetsize)) { failf(data, "Failed to receive SOCKS4 connect request ack."); return CURLE_COULDNT_CONNECT; } @@ -335,7 +335,7 @@ CURLcode Curl_SOCKS4(const char *proxy_name, } } - curlx_nonblock(sock, TRUE); + (void)curlx_nonblock(sock, TRUE); return CURLE_OK; /* Proxy was successful! */ } @@ -382,7 +382,7 @@ CURLcode Curl_SOCKS5(const char *proxy_name, /* RFC1928 chapter 5 specifies max 255 chars for domain name in packet */ if(!socks5_resolve_local && hostname_len > 255) { - infof(conn->data,"SOCKS5: server resolving disabled for hostnames of " + infof(conn->data, "SOCKS5: server resolving disabled for hostnames of " "length > 255 [actual len=%zu]\n", hostname_len); socks5_resolve_local = TRUE; } @@ -396,7 +396,7 @@ CURLcode Curl_SOCKS5(const char *proxy_name, return CURLE_OPERATION_TIMEDOUT; } - curlx_nonblock(sock, TRUE); + (void)curlx_nonblock(sock, TRUE); /* wait until socket gets connected */ result = Curl_socket_ready(CURL_SOCKET_BAD, sock, timeout); @@ -427,16 +427,16 @@ CURLcode Curl_SOCKS5(const char *proxy_name, socksreq[3] = 2; /* username/password */ #endif - curlx_nonblock(sock, FALSE); + (void)curlx_nonblock(sock, FALSE); code = Curl_write_plain(conn, sock, (char *)socksreq, (2 + (int)socksreq[1]), &written); - if((code != CURLE_OK) || (written != (2 + (int)socksreq[1]))) { + if(code || (written != (2 + (int)socksreq[1]))) { failf(data, "Unable to send initial SOCKS5 request."); return CURLE_COULDNT_CONNECT; } - curlx_nonblock(sock, TRUE); + (void)curlx_nonblock(sock, TRUE); result = Curl_socket_ready(sock, CURL_SOCKET_BAD, timeout); @@ -454,10 +454,10 @@ CURLcode Curl_SOCKS5(const char *proxy_name, return CURLE_RECV_ERROR; } - curlx_nonblock(sock, FALSE); + (void)curlx_nonblock(sock, FALSE); result=Curl_blockread_all(conn, sock, (char *)socksreq, 2, &actualread); - if((result != CURLE_OK) || (actualread != 2)) { + if(result || (actualread != 2)) { failf(data, "Unable to receive initial SOCKS5 response."); return CURLE_COULDNT_CONNECT; } @@ -473,7 +473,7 @@ CURLcode Curl_SOCKS5(const char *proxy_name, #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) else if(socksreq[1] == 1) { code = Curl_SOCKS5_gssapi_negotiate(sockindex, conn); - if(code != CURLE_OK) { + if(code) { failf(data, "Unable to negotiate SOCKS5 GSS-API context."); return CURLE_COULDNT_CONNECT; } @@ -510,13 +510,13 @@ CURLcode Curl_SOCKS5(const char *proxy_name, len += proxy_password_len; code = Curl_write_plain(conn, sock, (char *)socksreq, len, &written); - if((code != CURLE_OK) || (len != written)) { + if(code || (len != written)) { failf(data, "Failed to send SOCKS5 sub-negotiation request."); return CURLE_COULDNT_CONNECT; } result=Curl_blockread_all(conn, sock, (char *)socksreq, 2, &actualread); - if((result != CURLE_OK) || (actualread != 2)) { + if(result || (actualread != 2)) { failf(data, "Unable to receive SOCKS5 sub-negotiation response."); return CURLE_COULDNT_CONNECT; } @@ -583,7 +583,7 @@ CURLcode Curl_SOCKS5(const char *proxy_name, if(rc == CURLRESOLV_PENDING) { /* this requires that we're in "wait for resolve" state */ code = Curl_resolver_wait_resolv(conn, &dns); - if(code != CURLE_OK) + if(code) return code; } @@ -642,7 +642,7 @@ CURLcode Curl_SOCKS5(const char *proxy_name, #endif code = Curl_write_plain(conn, sock, (char *)socksreq, len, &written); - if((code != CURLE_OK) || (len != written)) { + if(code || (len != written)) { failf(data, "Failed to send SOCKS5 connect request."); return CURLE_COULDNT_CONNECT; } @@ -658,7 +658,7 @@ CURLcode Curl_SOCKS5(const char *proxy_name, result = Curl_blockread_all(conn, sock, (char *)socksreq, len, &actualread); - if((result != CURLE_OK) || (len != actualread)) { + if(result || (len != actualread)) { failf(data, "Failed to receive SOCKS5 connect request ack."); return CURLE_COULDNT_CONNECT; } @@ -738,7 +738,7 @@ CURLcode Curl_SOCKS5(const char *proxy_name, len -= 10; result = Curl_blockread_all(conn, sock, (char *)&socksreq[10], len, &actualread); - if((result != CURLE_OK) || (len != actualread)) { + if(result || (len != actualread)) { failf(data, "Failed to receive SOCKS5 connect request ack."); return CURLE_COULDNT_CONNECT; } @@ -747,7 +747,7 @@ CURLcode Curl_SOCKS5(const char *proxy_name, } #endif - curlx_nonblock(sock, TRUE); + (void)curlx_nonblock(sock, TRUE); return CURLE_OK; /* Proxy was successful! */ } diff --git a/Utilities/cmcurl/lib/socks_gssapi.c b/Utilities/cmcurl/lib/socks_gssapi.c index 0eaa74c..8e575c2 100644 --- a/Utilities/cmcurl/lib/socks_gssapi.c +++ b/Utilities/cmcurl/lib/socks_gssapi.c @@ -6,7 +6,7 @@ * \___|\___/|_| \_\_____| * * Copyright (C) 2009, 2011, Markus Moeller, <markus_moeller@compuserve.com> - * Copyright (C) 2012, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2012 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -23,16 +23,7 @@ #include "curl_setup.h" -#ifndef CURL_DISABLE_PROXY - -#ifdef HAVE_GSSAPI -#ifdef HAVE_OLD_GSSMIT -#define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name -#define NCOMPAT 1 -#endif -#ifndef gss_nt_service_name -#define gss_nt_service_name GSS_C_NT_HOSTBASED_SERVICE -#endif +#if defined(HAVE_GSSAPI) && !defined(CURL_DISABLE_PROXY) #include "curl_gssapi.h" #include "urldata.h" @@ -41,10 +32,7 @@ #include "timeval.h" #include "socks.h" #include "warnless.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - +#include "curl_printf.h" #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" @@ -60,7 +48,7 @@ static int check_gss_err(struct SessionHandle *data, const char* function) { if(GSS_ERROR(major_status)) { - OM_uint32 maj_stat,min_stat; + OM_uint32 maj_stat, min_stat; OM_uint32 msg_ctx = 0; gss_buffer_desc status_string; char buf[1024]; @@ -104,10 +92,10 @@ static int check_gss_err(struct SessionHandle *data, gss_release_buffer(&min_stat, &status_string); } failf(data, "GSS-API error: %s failed:\n%s", function, buf); - return(1); + return 1; } - return(0); + return 0; } CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, @@ -143,7 +131,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, */ /* prepare service name */ - if(strchr(serviceptr,'/')) { + if(strchr(serviceptr, '/')) { service.value = malloc(strlen(serviceptr)); if(!service.value) return CURLE_OUT_OF_MEMORY; @@ -162,13 +150,13 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, serviceptr, conn->proxy.name); gss_major_status = gss_import_name(&gss_minor_status, &service, - gss_nt_service_name, &server); + GSS_C_NT_HOSTBASED_SERVICE, &server); } gss_release_buffer(&gss_status, &service); /* clear allocated memory */ - if(check_gss_err(data,gss_major_status, - gss_minor_status,"gss_import_name()")) { + if(check_gss_err(data, gss_major_status, + gss_minor_status, "gss_import_name()")) { failf(data, "Failed to create service name."); gss_release_name(&gss_status, &server); return CURLE_COULDNT_CONNECT; @@ -185,12 +173,13 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, NULL, gss_token, &gss_send_token, + TRUE, &gss_ret_flags); if(gss_token != GSS_C_NO_BUFFER) gss_release_buffer(&gss_status, &gss_recv_token); - if(check_gss_err(data,gss_major_status, - gss_minor_status,"gss_init_sec_context")) { + if(check_gss_err(data, gss_major_status, + gss_minor_status, "gss_init_sec_context")) { gss_release_name(&gss_status, &server); gss_release_buffer(&gss_status, &gss_recv_token); gss_release_buffer(&gss_status, &gss_send_token); @@ -203,10 +192,10 @@ 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 != CURLE_OK) || (4 != written)) { + if(code || (4 != written)) { failf(data, "Failed to send GSS-API authentication request."); gss_release_name(&gss_status, &server); gss_release_buffer(&gss_status, &gss_recv_token); @@ -218,7 +207,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, code = Curl_write_plain(conn, sock, (char *)gss_send_token.value, gss_send_token.length, &written); - if((code != CURLE_OK) || ((ssize_t)gss_send_token.length != written)) { + if(code || ((ssize_t)gss_send_token.length != written)) { failf(data, "Failed to send GSS-API authentication token."); gss_release_name(&gss_status, &server); gss_release_buffer(&gss_status, &gss_recv_token); @@ -244,7 +233,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, */ result=Curl_blockread_all(conn, sock, (char *)socksreq, 4, &actualread); - if(result != CURLE_OK || actualread != 4) { + if(result || (actualread != 4)) { failf(data, "Failed to receive GSS-API authentication response."); gss_release_name(&gss_status, &server); gss_delete_sec_context(&gss_status, &gss_context, NULL); @@ -285,7 +274,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, result=Curl_blockread_all(conn, sock, (char *)gss_recv_token.value, gss_recv_token.length, &actualread); - if(result != CURLE_OK || actualread != us_length) { + if(result || (actualread != us_length)) { failf(data, "Failed to receive GSS-API authentication token."); gss_release_name(&gss_status, &server); gss_release_buffer(&gss_status, &gss_recv_token); @@ -302,8 +291,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, gss_major_status = gss_inquire_context (&gss_minor_status, gss_context, &gss_client_name, NULL, NULL, NULL, NULL, NULL, NULL); - if(check_gss_err(data,gss_major_status, - gss_minor_status,"gss_inquire_context")) { + if(check_gss_err(data, gss_major_status, + gss_minor_status, "gss_inquire_context")) { gss_delete_sec_context(&gss_status, &gss_context, NULL); gss_release_name(&gss_status, &gss_client_name); failf(data, "Failed to determine user name."); @@ -311,8 +300,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, } gss_major_status = gss_display_name(&gss_minor_status, gss_client_name, &gss_send_token, NULL); - if(check_gss_err(data,gss_major_status, - gss_minor_status,"gss_display_name")) { + if(check_gss_err(data, gss_major_status, + gss_minor_status, "gss_display_name")) { gss_delete_sec_context(&gss_status, &gss_context, NULL); gss_release_name(&gss_status, &gss_client_name); gss_release_buffer(&gss_status, &gss_send_token); @@ -383,7 +372,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; @@ -398,7 +387,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, GSS_C_QOP_DEFAULT, &gss_send_token, &gss_conf_state, &gss_w_token); - if(check_gss_err(data,gss_major_status,gss_minor_status,"gss_wrap")) { + if(check_gss_err(data, gss_major_status, gss_minor_status, "gss_wrap")) { gss_release_buffer(&gss_status, &gss_send_token); gss_release_buffer(&gss_status, &gss_w_token); gss_delete_sec_context(&gss_status, &gss_context, NULL); @@ -408,11 +397,11 @@ 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); - if((code != CURLE_OK) || (4 != written)) { + if(code || (4 != written)) { failf(data, "Failed to send GSS-API encryption request."); gss_release_buffer(&gss_status, &gss_w_token); gss_delete_sec_context(&gss_status, &gss_context, NULL); @@ -422,7 +411,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, if(data->set.socks5_gssapi_nec) { memcpy(socksreq, &gss_enc, 1); code = Curl_write_plain(conn, sock, socksreq, 1, &written); - if((code != CURLE_OK) || ( 1 != written)) { + if(code || ( 1 != written)) { failf(data, "Failed to send GSS-API encryption type."); gss_delete_sec_context(&gss_status, &gss_context, NULL); return CURLE_COULDNT_CONNECT; @@ -431,7 +420,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, else { code = Curl_write_plain(conn, sock, (char *)gss_w_token.value, gss_w_token.length, &written); - if((code != CURLE_OK) || ((ssize_t)gss_w_token.length != written)) { + if(code || ((ssize_t)gss_w_token.length != written)) { failf(data, "Failed to send GSS-API encryption type."); gss_release_buffer(&gss_status, &gss_w_token); gss_delete_sec_context(&gss_status, &gss_context, NULL); @@ -441,7 +430,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, } result=Curl_blockread_all(conn, sock, (char *)socksreq, 4, &actualread); - if(result != CURLE_OK || actualread != 4) { + if(result || (actualread != 4)) { failf(data, "Failed to receive GSS-API encryption response."); gss_delete_sec_context(&gss_status, &gss_context, NULL); return CURLE_COULDNT_CONNECT; @@ -474,7 +463,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, result=Curl_blockread_all(conn, sock, (char *)gss_recv_token.value, gss_recv_token.length, &actualread); - if(result != CURLE_OK || actualread != us_length) { + if(result || (actualread != us_length)) { failf(data, "Failed to receive GSS-API encryptrion type."); gss_release_buffer(&gss_status, &gss_recv_token); gss_delete_sec_context(&gss_status, &gss_context, NULL); @@ -486,7 +475,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, &gss_recv_token, &gss_w_token, 0, GSS_C_QOP_DEFAULT); - if(check_gss_err(data,gss_major_status,gss_minor_status,"gss_unwrap")) { + if(check_gss_err(data, gss_major_status, gss_minor_status, "gss_unwrap")) { gss_release_buffer(&gss_status, &gss_recv_token); gss_release_buffer(&gss_status, &gss_w_token); gss_delete_sec_context(&gss_status, &gss_context, NULL); @@ -503,7 +492,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, return CURLE_COULDNT_CONNECT; } - memcpy(socksreq,gss_w_token.value,gss_w_token.length); + memcpy(socksreq, gss_w_token.value, gss_w_token.length); gss_release_buffer(&gss_status, &gss_w_token); } else { @@ -515,7 +504,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, return CURLE_COULDNT_CONNECT; } - memcpy(socksreq,gss_recv_token.value,gss_recv_token.length); + memcpy(socksreq, gss_recv_token.value, gss_recv_token.length); gss_release_buffer(&gss_status, &gss_recv_token); } @@ -529,6 +518,5 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, return CURLE_OK; } -#endif -#endif /* CURL_DISABLE_PROXY */ +#endif /* HAVE_GSSAPI && !CURL_DISABLE_PROXY */ diff --git a/Utilities/cmcurl/lib/socks_sspi.c b/Utilities/cmcurl/lib/socks_sspi.c index 82684e0..a7708b2 100644 --- a/Utilities/cmcurl/lib/socks_sspi.c +++ b/Utilities/cmcurl/lib/socks_sspi.c @@ -5,8 +5,8 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * + * Copyright (C) 2012 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * Copyright (C) 2009, 2011, Markus Moeller, <markus_moeller@compuserve.com> - * Copyright (C) 2012 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -34,10 +34,7 @@ #include "curl_sspi.h" #include "curl_multibyte.h" #include "warnless.h" - -#define _MPRINTF_REPLACE /* use the internal *printf() functions */ -#include <curl/mprintf.h> - +#include "curl_printf.h" #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" @@ -107,8 +104,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, service_name = malloc(strlen(service) + strlen(conn->proxy.name) + 2); if(!service_name) return CURLE_OUT_OF_MEMORY; - snprintf(service_name,strlen(service) +strlen(conn->proxy.name)+2,"%s/%s", - service,conn->proxy.name); + snprintf(service_name, strlen(service) +strlen(conn->proxy.name)+2, + "%s/%s", service, conn->proxy.name); } input_desc.cBuffers = 1; @@ -146,7 +143,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, if(check_sspi_err(conn, status, "AcquireCredentialsHandle")) { failf(data, "Failed to acquire credentials."); - Curl_safefree(service_name); + free(service_name); s_pSecFn->FreeCredentialsHandle(&cred_handle); return CURLE_COULDNT_CONNECT; } @@ -185,7 +182,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, } if(check_sspi_err(conn, status, "InitializeSecurityContext")) { - Curl_safefree(service_name); + free(service_name); s_pSecFn->FreeCredentialsHandle(&cred_handle); s_pSecFn->DeleteSecurityContext(&sspi_context); if(sspi_recv_token.pvBuffer) @@ -201,9 +198,9 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, memcpy(socksreq+2, &us_length, sizeof(short)); code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written); - if((code != CURLE_OK) || (4 != written)) { + if(code || (4 != written)) { failf(data, "Failed to send SSPI authentication request."); - Curl_safefree(service_name); + free(service_name); if(sspi_send_token.pvBuffer) s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); if(sspi_recv_token.pvBuffer) @@ -215,9 +212,9 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, code = Curl_write_plain(conn, sock, (char *)sspi_send_token.pvBuffer, sspi_send_token.cbBuffer, &written); - if((code != CURLE_OK) || (sspi_send_token.cbBuffer != (size_t)written)) { + if(code || (sspi_send_token.cbBuffer != (size_t)written)) { failf(data, "Failed to send SSPI authentication token."); - Curl_safefree(service_name); + free(service_name); if(sspi_send_token.pvBuffer) s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); if(sspi_recv_token.pvBuffer) @@ -255,9 +252,9 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, */ result = Curl_blockread_all(conn, sock, (char *)socksreq, 4, &actualread); - if(result != CURLE_OK || actualread != 4) { + if(result || (actualread != 4)) { failf(data, "Failed to receive SSPI authentication response."); - Curl_safefree(service_name); + free(service_name); s_pSecFn->FreeCredentialsHandle(&cred_handle); s_pSecFn->DeleteSecurityContext(&sspi_context); return CURLE_COULDNT_CONNECT; @@ -267,7 +264,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, if(socksreq[1] == 255) { /* status / message type */ failf(data, "User was rejected by the SOCKS5 server (%u %u).", (unsigned int)socksreq[0], (unsigned int)socksreq[1]); - Curl_safefree(service_name); + free(service_name); s_pSecFn->FreeCredentialsHandle(&cred_handle); s_pSecFn->DeleteSecurityContext(&sspi_context); return CURLE_COULDNT_CONNECT; @@ -276,7 +273,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, if(socksreq[1] != 1) { /* status / messgae type */ failf(data, "Invalid SSPI authentication response type (%u %u).", (unsigned int)socksreq[0], (unsigned int)socksreq[1]); - Curl_safefree(service_name); + free(service_name); s_pSecFn->FreeCredentialsHandle(&cred_handle); s_pSecFn->DeleteSecurityContext(&sspi_context); return CURLE_COULDNT_CONNECT; @@ -289,7 +286,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, sspi_recv_token.pvBuffer = malloc(us_length); if(!sspi_recv_token.pvBuffer) { - Curl_safefree(service_name); + free(service_name); s_pSecFn->FreeCredentialsHandle(&cred_handle); s_pSecFn->DeleteSecurityContext(&sspi_context); return CURLE_OUT_OF_MEMORY; @@ -297,9 +294,9 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, result = Curl_blockread_all(conn, sock, (char *)sspi_recv_token.pvBuffer, sspi_recv_token.cbBuffer, &actualread); - if(result != CURLE_OK || actualread != us_length) { + if(result || (actualread != us_length)) { failf(data, "Failed to receive SSPI authentication token."); - Curl_safefree(service_name); + free(service_name); if(sspi_recv_token.pvBuffer) s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); s_pSecFn->FreeCredentialsHandle(&cred_handle); @@ -310,7 +307,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, context_handle = &sspi_context; } - Curl_safefree(service_name); + free(service_name); /* Everything is good so far, user was authenticated! */ status = s_pSecFn->QueryCredentialsAttributes(&cred_handle, @@ -405,7 +402,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, return CURLE_OUT_OF_MEMORY; } - memcpy(sspi_w_token[1].pvBuffer,&gss_enc,1); + memcpy(sspi_w_token[1].pvBuffer, &gss_enc, 1); sspi_w_token[2].BufferType = SECBUFFER_PADDING; sspi_w_token[2].cbBuffer = sspi_sizes.cbBlockSize; sspi_w_token[2].pvBuffer = malloc(sspi_sizes.cbBlockSize); @@ -459,11 +456,11 @@ 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); - if((code != CURLE_OK) || (4 != written)) { + if(code || (4 != written)) { failf(data, "Failed to send SSPI encryption request."); if(sspi_send_token.pvBuffer) s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); @@ -472,9 +469,9 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, } if(data->set.socks5_gssapi_nec) { - memcpy(socksreq,&gss_enc,1); + memcpy(socksreq, &gss_enc, 1); code = Curl_write_plain(conn, sock, (char *)socksreq, 1, &written); - if((code != CURLE_OK) || (1 != written)) { + if(code || (1 != written)) { failf(data, "Failed to send SSPI encryption type."); s_pSecFn->DeleteSecurityContext(&sspi_context); return CURLE_COULDNT_CONNECT; @@ -483,7 +480,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, else { code = Curl_write_plain(conn, sock, (char *)sspi_send_token.pvBuffer, sspi_send_token.cbBuffer, &written); - if((code != CURLE_OK) || (sspi_send_token.cbBuffer != (size_t)written)) { + if(code || (sspi_send_token.cbBuffer != (size_t)written)) { failf(data, "Failed to send SSPI encryption type."); if(sspi_send_token.pvBuffer) s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); @@ -495,7 +492,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, } result = Curl_blockread_all(conn, sock, (char *)socksreq, 4, &actualread); - if(result != CURLE_OK || actualread != 4) { + if(result || (actualread != 4)) { failf(data, "Failed to receive SSPI encryption response."); s_pSecFn->DeleteSecurityContext(&sspi_context); return CURLE_COULDNT_CONNECT; @@ -529,7 +526,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, result = Curl_blockread_all(conn, sock, (char *)sspi_w_token[0].pvBuffer, sspi_w_token[0].cbBuffer, &actualread); - if(result != CURLE_OK || actualread != us_length) { + if(result || (actualread != us_length)) { failf(data, "Failed to receive SSPI encryption type."); s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); s_pSecFn->DeleteSecurityContext(&sspi_context); @@ -570,7 +567,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, return CURLE_COULDNT_CONNECT; } - memcpy(socksreq,sspi_w_token[1].pvBuffer,sspi_w_token[1].cbBuffer); + memcpy(socksreq, sspi_w_token[1].pvBuffer, sspi_w_token[1].cbBuffer); s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); } @@ -582,7 +579,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, s_pSecFn->DeleteSecurityContext(&sspi_context); return CURLE_COULDNT_CONNECT; } - memcpy(socksreq,sspi_w_token[0].pvBuffer,sspi_w_token[0].cbBuffer); + memcpy(socksreq, sspi_w_token[0].pvBuffer, sspi_w_token[0].cbBuffer); s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); } diff --git a/Utilities/cmcurl/lib/splay.c b/Utilities/cmcurl/lib/splay.c index 5bb7065..b87b6cf 100644 --- a/Utilities/cmcurl/lib/splay.c +++ b/Utilities/cmcurl/lib/splay.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1997 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1997 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -101,13 +101,13 @@ struct Curl_tree *Curl_splayinsert(struct timeval i, struct Curl_tree *t, struct Curl_tree *node) { - static const struct timeval KEY_NOTUSED = {-1,-1}; /* will *NEVER* appear */ + static const struct timeval KEY_NOTUSED = {-1, -1}; /* will *NEVER* appear */ if(node == NULL) return t; if(t != NULL) { - t = Curl_splay(i,t); + t = Curl_splay(i, t); if(compare(i, t->key)==0) { /* There already exists a node in the tree with the very same key. Build a linked list of nodes. We make the new 'node' struct the new master @@ -162,7 +162,7 @@ struct Curl_tree *Curl_splaygetbest(struct timeval i, return NULL; } - t = Curl_splay(i,t); + t = Curl_splay(i, t); if(compare(i, t->key) < 0) { /* too big node, try the smaller chain */ if(t->smaller) @@ -223,7 +223,7 @@ 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 timeval KEY_NOTUSED = {-1, -1}; /* will *NEVER* appear */ struct Curl_tree *x; if(!t || !removenode) diff --git a/Utilities/cmcurl/lib/ssh.c b/Utilities/cmcurl/lib/ssh.c index 887e10f..94195a7 100644 --- a/Utilities/cmcurl/lib/ssh.c +++ b/Utilities/cmcurl/lib/ssh.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -83,10 +83,7 @@ #include "multiif.h" #include "select.h" #include "warnless.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - +#include "curl_printf.h" #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" @@ -94,6 +91,9 @@ #ifdef WIN32 # undef PATH_MAX # define PATH_MAX MAX_PATH +# ifndef R_OK +# define R_OK 4 +# endif #endif #ifndef PATH_MAX @@ -543,6 +543,17 @@ static CURLcode ssh_knownhost(struct connectdata *conn) keybit = (keytype == LIBSSH2_HOSTKEY_TYPE_RSA)? LIBSSH2_KNOWNHOST_KEY_SSHRSA:LIBSSH2_KNOWNHOST_KEY_SSHDSS; +#ifdef HAVE_LIBSSH2_KNOWNHOST_CHECKP + keycheck = libssh2_knownhost_checkp(sshc->kh, + conn->host.name, + (conn->remote_port != PORT_SSH)? + conn->remote_port:-1, + remotekey, keylen, + LIBSSH2_KNOWNHOST_TYPE_PLAIN| + LIBSSH2_KNOWNHOST_KEYENC_RAW| + keybit, + &host); +#else keycheck = libssh2_knownhost_check(sshc->kh, conn->host.name, remotekey, keylen, @@ -550,6 +561,7 @@ static CURLcode ssh_knownhost(struct connectdata *conn) LIBSSH2_KNOWNHOST_KEYENC_RAW| keybit, &host); +#endif infof(data, "SSH host check: %d, key: %s\n", keycheck, (keycheck <= LIBSSH2_KNOWNHOST_CHECK_MISMATCH)? @@ -588,8 +600,10 @@ static CURLcode ssh_knownhost(struct connectdata *conn) switch(rc) { default: /* unknown return codes will equal reject */ + /* FALLTHROUGH */ case CURLKHSTAT_REJECT: state(conn, SSH_SESSION_FREE); + /* FALLTHROUGH */ case CURLKHSTAT_DEFER: /* DEFER means bail out but keep the SSH_HOSTKEY state */ result = sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION; @@ -732,7 +746,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) * whatever) is up to us. */ result = ssh_check_fingerprint(conn); - if(result == CURLE_OK) + if(!result) state(conn, SSH_AUTHLIST); /* ssh_check_fingerprint sets state appropriately on error */ break; @@ -786,7 +800,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) if((data->set.ssh_auth_types & CURLSSH_AUTH_PUBLICKEY) && (strstr(sshc->authlist, "publickey") != NULL)) { char *home = NULL; - bool rsa_pub_empty_but_ok = FALSE; + bool out_of_memory = FALSE; sshc->rsa_pub = sshc->rsa = NULL; @@ -794,34 +808,55 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) HOME environment variable etc? */ home = curl_getenv("HOME"); - if(data->set.str[STRING_SSH_PUBLIC_KEY] && - !*data->set.str[STRING_SSH_PUBLIC_KEY]) - rsa_pub_empty_but_ok = true; - else if(data->set.str[STRING_SSH_PUBLIC_KEY]) - sshc->rsa_pub = aprintf("%s", data->set.str[STRING_SSH_PUBLIC_KEY]); - else if(home) - sshc->rsa_pub = aprintf("%s/.ssh/id_dsa.pub", home); - else - /* as a final resort, try current dir! */ - sshc->rsa_pub = strdup("id_dsa.pub"); - - if(!rsa_pub_empty_but_ok && (sshc->rsa_pub == NULL)) { - Curl_safefree(home); - state(conn, SSH_SESSION_FREE); - sshc->actualcode = CURLE_OUT_OF_MEMORY; - break; + if(data->set.str[STRING_SSH_PRIVATE_KEY]) + sshc->rsa = strdup(data->set.str[STRING_SSH_PRIVATE_KEY]); + else { + /* If no private key file is specified, try some common paths. */ + if(home) { + /* Try ~/.ssh first. */ + sshc->rsa = aprintf("%s/.ssh/id_rsa", home); + if(!sshc->rsa) + out_of_memory = TRUE; + else if(access(sshc->rsa, R_OK) != 0) { + Curl_safefree(sshc->rsa); + sshc->rsa = aprintf("%s/.ssh/id_dsa", home); + if(!sshc->rsa) + out_of_memory = TRUE; + else if(access(sshc->rsa, R_OK) != 0) { + Curl_safefree(sshc->rsa); + } + } + } + if(!out_of_memory && !sshc->rsa) { + /* Nothing found; try the current dir. */ + sshc->rsa = strdup("id_rsa"); + if(sshc->rsa && access(sshc->rsa, R_OK) != 0) { + Curl_safefree(sshc->rsa); + sshc->rsa = strdup("id_dsa"); + if(sshc->rsa && access(sshc->rsa, R_OK) != 0) { + Curl_safefree(sshc->rsa); + /* Out of guesses. Set to the empty string to avoid + * surprising info messages. */ + sshc->rsa = strdup(""); + } + } + } } - if(data->set.str[STRING_SSH_PRIVATE_KEY]) - sshc->rsa = aprintf("%s", data->set.str[STRING_SSH_PRIVATE_KEY]); - else if(home) - sshc->rsa = aprintf("%s/.ssh/id_dsa", home); - else - /* as a final resort, try current dir! */ - sshc->rsa = strdup("id_dsa"); + /* + * Unless the user explicitly specifies a public key file, let + * libssh2 extract the public key from the private key file. + * This is done by simply passing sshc->rsa_pub = NULL. + */ + if(data->set.str[STRING_SSH_PUBLIC_KEY]) { + sshc->rsa_pub = strdup(data->set.str[STRING_SSH_PUBLIC_KEY]); + if(!sshc->rsa_pub) + out_of_memory = TRUE; + } - if(sshc->rsa == NULL) { - Curl_safefree(home); + if(out_of_memory || sshc->rsa == NULL) { + free(home); + Curl_safefree(sshc->rsa); Curl_safefree(sshc->rsa_pub); state(conn, SSH_SESSION_FREE); sshc->actualcode = CURLE_OUT_OF_MEMORY; @@ -832,10 +867,10 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) if(!sshc->passphrase) sshc->passphrase = ""; - Curl_safefree(home); + free(home); - infof(data, "Using ssh public key file %s\n", sshc->rsa_pub); - infof(data, "Using ssh private key file %s\n", sshc->rsa); + infof(data, "Using SSH public key file '%s'\n", sshc->rsa_pub); + infof(data, "Using SSH private key file '%s'\n", sshc->rsa); state(conn, SSH_AUTH_PKEY); } @@ -900,6 +935,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) } else { state(conn, SSH_AUTH_HOST_INIT); + rc = 0; /* clear rc and continue */ } break; @@ -984,11 +1020,11 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) sshc->sshagent_identity); if(rc < 0) { - if(rc != LIBSSH2_ERROR_EAGAIN) { + if(rc != LIBSSH2_ERROR_EAGAIN) /* tried and failed? go to next identity */ sshc->sshagent_prev_identity = sshc->sshagent_identity; - } - break; + else + break; } } @@ -1002,8 +1038,10 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) infof(data, "Agent based authentication successful\n"); state(conn, SSH_AUTH_DONE); } - else + else { state(conn, SSH_AUTH_KEY_INIT); + rc = 0; /* clear rc and continue */ + } #endif break; @@ -1702,8 +1740,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) BUFSIZE : curlx_sotouz(data->state.resume_from - passed); size_t actuallyread = - conn->fread_func(data->state.buffer, 1, readthisamountnow, - conn->fread_in); + data->set.fread_func(data->state.buffer, 1, readthisamountnow, + data->set.in); passed += actuallyread; if((actuallyread == 0) || (actuallyread > readthisamountnow)) { @@ -1770,7 +1808,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) break; case SSH_SFTP_CREATE_DIRS: - if((sshc->slash_pos = strchr(sshc->slash_pos, '/')) != NULL) { + sshc->slash_pos = strchr(sshc->slash_pos, '/'); + if(sshc->slash_pos) { *sshc->slash_pos = 0; infof(data, "Creating directory '%s'\n", sftp_scp->path); @@ -1882,7 +1921,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) } result = Curl_client_write(conn, CLIENTWRITE_BODY, tmpLine, sshc->readdir_len+1); - Curl_safefree(tmpLine); + free(tmpLine); if(result) { state(conn, SSH_STOP); @@ -1998,7 +2037,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) sshc->readdir_line, sshc->readdir_currLen); - if(result == CURLE_OK) { + if(!result) { /* output debug output if that is requested */ if(data->set.verbose) { @@ -2068,10 +2107,14 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) if(rc == LIBSSH2_ERROR_EAGAIN) { break; } - else if(rc) { + else if(rc || + !(attrs.flags & LIBSSH2_SFTP_ATTR_SIZE) || + (attrs.filesize == 0)) { /* * libssh2_sftp_open() didn't return an error, so maybe the server * just doesn't support stat() + * OR the server doesn't return a file size with a stat() + * OR file size is 0 */ data->req.size = -1; data->req.maxdownload = -1; @@ -2101,7 +2144,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) /* from is relative to end of file */ from += size; } - if(from >= size) { + if(from > size) { failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")", from, attrs.filesize); @@ -2202,7 +2245,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) DEBUGF(infof(data, "SFTP DONE done\n")); /* Check if nextstate is set and move .nextstate could be POSTQUOTE_INIT - After nextstate is executed,the control should come back to + After nextstate is executed, the control should come back to SSH_SFTP_CLOSE to pass the correct result back */ if(sshc->nextstate != SSH_NO_STATE && sshc->nextstate != SSH_SFTP_CLOSE) { @@ -2691,7 +2734,7 @@ static CURLcode ssh_block_statemach(struct connectdata *conn, } #ifdef HAVE_LIBSSH2_SESSION_BLOCK_DIRECTION - if((CURLE_OK == result) && block) { + if(!result && block) { int dir = libssh2_session_block_directions(sshc->ssh_session); curl_socket_t sock = conn->sock[FIRSTSOCKET]; curl_socket_t fd_read = CURL_SOCKET_BAD; @@ -2863,7 +2906,7 @@ static CURLcode scp_doing(struct connectdata *conn, static CURLcode ssh_do(struct connectdata *conn, bool *done) { - CURLcode res; + CURLcode result; bool connected = 0; struct SessionHandle *data = conn->data; struct ssh_conn *sshc = &conn->proto.sshc; @@ -2882,11 +2925,11 @@ static CURLcode ssh_do(struct connectdata *conn, bool *done) Curl_pgrsSetDownloadSize(data, -1); if(conn->handler->protocol & CURLPROTO_SCP) - res = scp_perform(conn, &connected, done); + result = scp_perform(conn, &connected, done); else - res = sftp_perform(conn, &connected, done); + result = sftp_perform(conn, &connected, done); - return res; + return result; } /* BLOCKING, but the function is using the state machine so the only reason @@ -2918,7 +2961,7 @@ static CURLcode ssh_done(struct connectdata *conn, CURLcode status) CURLcode result = CURLE_OK; struct SSHPROTO *sftp_scp = conn->data->req.protop; - if(status == CURLE_OK) { + if(!status) { /* run the state-machine TODO: when the multi interface is used, this _really_ should be using @@ -2946,7 +2989,7 @@ static CURLcode scp_done(struct connectdata *conn, CURLcode status, { (void)premature; /* not used */ - if(status == CURLE_OK) + if(!status) state(conn, SSH_SCP_DONE); return ssh_done(conn, status); @@ -3044,8 +3087,7 @@ CURLcode sftp_perform(struct connectdata *conn, static CURLcode sftp_doing(struct connectdata *conn, bool *dophase_done) { - CURLcode result; - result = ssh_multi_statemach(conn, dophase_done); + CURLcode result = ssh_multi_statemach(conn, dophase_done); if(*dophase_done) { DEBUGF(infof(conn->data, "DO phase is complete\n")); @@ -3082,7 +3124,7 @@ static CURLcode sftp_done(struct connectdata *conn, CURLcode status, { struct ssh_conn *sshc = &conn->proto.sshc; - if(status == CURLE_OK) { + if(!status) { /* Post quote commands are executed after the SFTP_CLOSE state to avoid errors that could happen due to open file handles during POSTQUOTE operation */ @@ -3228,8 +3270,8 @@ get_pathname(const char **cpp, char **path) return CURLE_OK; fail: - Curl_safefree(*path); - return CURLE_QUOTE_ERROR; + Curl_safefree(*path); + return CURLE_QUOTE_ERROR; } diff --git a/Utilities/cmcurl/lib/ssh.h b/Utilities/cmcurl/lib/ssh.h index ff2e16b..b3cc54c 100644 --- a/Utilities/cmcurl/lib/ssh.h +++ b/Utilities/cmcurl/lib/ssh.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -44,9 +44,9 @@ typedef enum { SSH_AUTH_PKEY, SSH_AUTH_PASS_INIT, SSH_AUTH_PASS, - SSH_AUTH_AGENT_INIT,/* initialize then wait for connection to agent */ - SSH_AUTH_AGENT_LIST,/* ask for list then wait for entire list to come */ - SSH_AUTH_AGENT, /* attempt one key at a time */ + SSH_AUTH_AGENT_INIT, /* initialize then wait for connection to agent */ + SSH_AUTH_AGENT_LIST, /* ask for list then wait for entire list to come */ + SSH_AUTH_AGENT, /* attempt one key at a time */ SSH_AUTH_HOST_INIT, SSH_AUTH_HOST, SSH_AUTH_KEY_INIT, @@ -158,22 +158,34 @@ struct ssh_conn { #ifdef USE_LIBSSH2 +/* Feature detection based on version numbers to better work with + non-configure platforms */ + #if !defined(LIBSSH2_VERSION_NUM) || (LIBSSH2_VERSION_NUM < 0x001000) # error "SCP/SFTP protocols require libssh2 0.16 or later" #endif -#if defined(LIBSSH2_VERSION_NUM) && (LIBSSH2_VERSION_NUM >= 0x010000) -# define HAVE_LIBSSH2_SFTP_SEEK64 1 -#else -# undef HAVE_LIBSSH2_SFTP_SEEK64 +#if LIBSSH2_VERSION_NUM >= 0x010000 +#define HAVE_LIBSSH2_SFTP_SEEK64 1 +#endif + +#if LIBSSH2_VERSION_NUM >= 0x010100 +#define HAVE_LIBSSH2_VERSION 1 #endif -#if defined(LIBSSH2_VERSION_NUM) && (LIBSSH2_VERSION_NUM >= 0x010206) -# define HAVE_LIBSSH2_SCP_SEND64 1 -#else -# undef HAVE_LIBSSH2_SCP_SEND64 +#if LIBSSH2_VERSION_NUM >= 0x010205 +#define HAVE_LIBSSH2_INIT 1 +#define HAVE_LIBSSH2_EXIT 1 #endif +#if LIBSSH2_VERSION_NUM >= 0x010206 +#define HAVE_LIBSSH2_KNOWNHOST_CHECKP 1 +#define HAVE_LIBSSH2_SCP_SEND64 1 +#endif + +#if LIBSSH2_VERSION_NUM >= 0x010208 +#define HAVE_LIBSSH2_SESSION_HANDSHAKE 1 +#endif extern const struct Curl_handler Curl_handler_scp; extern const struct Curl_handler Curl_handler_sftp; diff --git a/Utilities/cmcurl/lib/strdup.c b/Utilities/cmcurl/lib/strdup.c index 3b776b1..5685b81 100644 --- a/Utilities/cmcurl/lib/strdup.c +++ b/Utilities/cmcurl/lib/strdup.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -19,12 +19,12 @@ * KIND, either express or implied. * ***************************************************************************/ -/* - * This file is 'mem-include-scan' clean. See test 1132. - */ #include "curl_setup.h" - #include "strdup.h" +#include "curl_memory.h" + +/* The last #include file should be: */ +#include "memdebug.h" #ifndef HAVE_STRDUP char *curlx_strdup(const char *str) @@ -44,9 +44,30 @@ char *curlx_strdup(const char *str) if(!newstr) return (char *)NULL; - memcpy(newstr,str,(len+1)*sizeof(char)); + memcpy(newstr, str, (len+1)*sizeof(char)); return newstr; } #endif + +/*************************************************************************** + * + * Curl_memdup(source, length) + * + * Copies the 'source' data to a newly allocated buffer (that is + * returned). Copies 'length' bytes. + * + * Returns the new pointer or NULL on failure. + * + ***************************************************************************/ +char *Curl_memdup(const char *src, size_t length) +{ + char *buffer = malloc(length); + if(!buffer) + return NULL; /* fail */ + + memcpy(buffer, src, length); + + return buffer; +} diff --git a/Utilities/cmcurl/lib/strdup.h b/Utilities/cmcurl/lib/strdup.h index 49af911..23a71f8 100644 --- a/Utilities/cmcurl/lib/strdup.h +++ b/Utilities/cmcurl/lib/strdup.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -26,5 +26,6 @@ #ifndef HAVE_STRDUP extern char *curlx_strdup(const char *str); #endif +char *Curl_memdup(const char *src, size_t buffer_length); #endif /* HEADER_CURL_STRDUP_H */ diff --git a/Utilities/cmcurl/lib/strerror.c b/Utilities/cmcurl/lib/strerror.c index 66033f2..5657141 100644 --- a/Utilities/cmcurl/lib/strerror.c +++ b/Utilities/cmcurl/lib/strerror.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2004 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2004 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -40,10 +40,7 @@ #endif #include "strerror.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - +#include "curl_printf.h" #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" @@ -298,6 +295,12 @@ curl_easy_strerror(CURLcode error) case CURLE_NO_CONNECTION_AVAILABLE: return "The max connection limit is reached"; + case CURLE_SSL_PINNEDPUBKEYNOTMATCH: + return "SSL public key does not match pinned public key"; + + case CURLE_SSL_INVALIDCERTSTATUS: + return "SSL server certificate status verification FAILED"; + /* error codes not used by current libcurl */ case CURLE_OBSOLETE20: case CURLE_OBSOLETE24: @@ -327,7 +330,7 @@ curl_easy_strerror(CURLcode error) */ return "Unknown error"; #else - if(error == CURLE_OK) + if(!error) return "No error"; else return "Error"; @@ -594,7 +597,7 @@ get_winsock_error (int err, char *buf, size_t len) return NULL; } #else - if(err == CURLE_OK) + if(!err) return NULL; else p = "error"; @@ -638,7 +641,7 @@ const char *Curl_strerror(struct connectdata *conn, int err) FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, LANG_NEUTRAL, wbuf, sizeof(wbuf)/sizeof(wchar_t), NULL); - wcstombs(buf,wbuf,max); + wcstombs(buf, wbuf, max); } #else /* 'sys_nerr' is the maximum errno number, it is not widely portable */ @@ -705,9 +708,9 @@ const char *Curl_strerror(struct connectdata *conn, int err) buf[max] = '\0'; /* make sure the string is zero terminated */ /* strip trailing '\r\n' or '\n'. */ - if((p = strrchr(buf,'\n')) != NULL && (p - buf) >= 2) + if((p = strrchr(buf, '\n')) != NULL && (p - buf) >= 2) *p = '\0'; - if((p = strrchr(buf,'\r')) != NULL && (p - buf) >= 1) + if((p = strrchr(buf, '\r')) != NULL && (p - buf) >= 1) *p = '\0'; if(old_errno != ERRNO) @@ -821,6 +824,9 @@ const char *Curl_sspi_strerror (struct connectdata *conn, int err) case SEC_E_OK: txt = "No error"; break; + case CRYPT_E_REVOKED: + txt = "CRYPT_E_REVOKED"; + break; case SEC_E_ALGORITHM_MISMATCH: txt = "SEC_E_ALGORITHM_MISMATCH"; break; @@ -1064,6 +1070,12 @@ const char *Curl_sspi_strerror (struct connectdata *conn, int err) if(err == SEC_E_OK) strncpy(outbuf, txt, outmax); + else if(err == SEC_E_ILLEGAL_MESSAGE) + snprintf(outbuf, outmax, + "SEC_E_ILLEGAL_MESSAGE (0x%04X%04X) - This error usually occurs " + "when a fatal SSL/TLS alert is received (e.g. handshake failed). " + "More detail may be available in the Windows System event log.", + (err >> 16) & 0xffff, err & 0xffff); else { str = txtbuf; snprintf(txtbuf, sizeof(txtbuf), "%s (0x%04X%04X)", @@ -1079,7 +1091,7 @@ const char *Curl_sspi_strerror (struct connectdata *conn, int err) FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err, LANG_NEUTRAL, wbuf, sizeof(wbuf)/sizeof(wchar_t), NULL)) { - wcstombs(msgbuf,wbuf,sizeof(msgbuf)-1); + wcstombs(msgbuf, wbuf, sizeof(msgbuf)-1); msg_formatted = TRUE; } } @@ -1094,9 +1106,9 @@ const char *Curl_sspi_strerror (struct connectdata *conn, int err) if(msg_formatted) { msgbuf[sizeof(msgbuf)-1] = '\0'; /* strip trailing '\r\n' or '\n' */ - if((p = strrchr(msgbuf,'\n')) != NULL && (p - msgbuf) >= 2) + if((p = strrchr(msgbuf, '\n')) != NULL && (p - msgbuf) >= 2) *p = '\0'; - if((p = strrchr(msgbuf,'\r')) != NULL && (p - msgbuf) >= 1) + if((p = strrchr(msgbuf, '\r')) != NULL && (p - msgbuf) >= 1) *p = '\0'; msg = msgbuf; } diff --git a/Utilities/cmcurl/lib/strtoofft.h b/Utilities/cmcurl/lib/strtoofft.h index b812a67..75c73d4 100644 --- a/Utilities/cmcurl/lib/strtoofft.h +++ b/Utilities/cmcurl/lib/strtoofft.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -45,7 +45,14 @@ # define curlx_strtoofft strtoll # else # if defined(_MSC_VER) && (_MSC_VER >= 1300) && (_INTEGRAL_MAX_BITS >= 64) - _CRTIMP __int64 __cdecl _strtoi64(const char *, char **, int); +# 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); diff --git a/Utilities/cmcurl/lib/telnet.c b/Utilities/cmcurl/lib/telnet.c index 1f03a00..aabf99d 100644 --- a/Utilities/cmcurl/lib/telnet.c +++ b/Utilities/cmcurl/lib/telnet.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -51,21 +51,19 @@ #include "telnet.h" #include "connect.h" #include "progress.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> +#include "curl_printf.h" #define TELOPTS #define TELCMDS #include "arpa_telnet.h" -#include "curl_memory.h" #include "select.h" #include "strequal.h" #include "rawstr.h" #include "warnless.h" -/* The last #include file should be: */ +/* The last #include files should be: */ +#include "curl_memory.h" #include "memdebug.h" #define SUBBUFSIZE 512 @@ -228,9 +226,9 @@ check_wsock2 ( struct SessionHandle *data ) if(LOBYTE(wsaData.wVersion) != LOBYTE(wVersionRequested) || HIBYTE(wsaData.wVersion) != HIBYTE(wVersionRequested)) { /* Our version isn't supported */ - failf(data,"insufficient winsock version to support " - "telnet"); - return CURLE_FAILED_INIT; + failf(data, "insufficient winsock version to support " + "telnet"); + return CURLE_FAILED_INIT; } /* Our version is supported */ @@ -710,7 +708,6 @@ static void printsub(struct SessionHandle *data, size_t length) /* length of suboption data */ { unsigned int i = 0; - unsigned short *pval; if(data->set.verbose) { if(direction) { @@ -763,9 +760,9 @@ static void printsub(struct SessionHandle *data, switch(pointer[0]) { case CURL_TELOPT_NAWS: - pval = (unsigned short*)(pointer+1); - infof(data, "Width: %hu ; Height: %hu", - ntohs(pval[0]), ntohs(pval[1])); + if(length > 4) + infof(data, "Width: %hu ; Height: %hu", (pointer[1]<<8) | pointer[2], + (pointer[3]<<8) | pointer[4]); break; default: switch(pointer[1]) { @@ -1076,7 +1073,7 @@ CURLcode telrcv(struct connectdata *conn, CLIENTWRITE_BODY, \ (char *)&inbuf[startwrite], \ in-startwrite); \ - if(result != CURLE_OK) \ + if(result) \ return result; \ } \ startwrite = -1 @@ -1177,7 +1174,7 @@ CURLcode telrcv(struct connectdata *conn, if(c == CURL_IAC) tn->telrcv_state = CURL_TS_SE; else - CURL_SB_ACCUM(tn,c); + CURL_SB_ACCUM(tn, c); break; case CURL_TS_SE: @@ -1202,7 +1199,7 @@ CURLcode telrcv(struct connectdata *conn, tn->telrcv_state = CURL_TS_IAC; goto process_iac; } - CURL_SB_ACCUM(tn,c); + CURL_SB_ACCUM(tn, c); tn->telrcv_state = CURL_TS_SB; } else @@ -1230,9 +1227,9 @@ static CURLcode send_telnet_data(struct connectdata *conn, unsigned char outbuf[2]; ssize_t bytes_written, total_written; int out_count; - CURLcode rc = CURLE_OK; + CURLcode result = CURLE_OK; - while(rc == CURLE_OK && nread--) { + while(!result && nread--) { outbuf[0] = *buffer++; out_count = 1; if(outbuf[0] == CURL_IAC) @@ -1247,19 +1244,20 @@ static CURLcode send_telnet_data(struct connectdata *conn, switch (Curl_poll(pfd, 1, -1)) { case -1: /* error, abort writing */ case 0: /* timeout (will never happen) */ - rc = CURLE_SEND_ERROR; + result = CURLE_SEND_ERROR; break; default: /* write! */ bytes_written = 0; - rc = Curl_write(conn, conn->sock[FIRSTSOCKET], outbuf+total_written, - out_count-total_written, &bytes_written); + result = Curl_write(conn, conn->sock[FIRSTSOCKET], + outbuf+total_written, out_count-total_written, + &bytes_written); total_written += bytes_written; break; } - /* handle partial write */ - } while(rc == CURLE_OK && total_written < out_count); + /* handle partial write */ + } while(!result && total_written < out_count); } - return rc; + return result; } static CURLcode telnet_done(struct connectdata *conn, @@ -1282,7 +1280,7 @@ static CURLcode telnet_done(struct connectdata *conn, static CURLcode telnet_do(struct connectdata *conn, bool *done) { - CURLcode code; + CURLcode result; struct SessionHandle *data = conn->data; curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; #ifdef USE_WINSOCK @@ -1315,65 +1313,61 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) *done = TRUE; /* unconditionally */ - code = init_telnet(conn); - if(code) - return code; + result = init_telnet(conn); + if(result) + return result; tn = (struct TELNET *)data->req.protop; - code = check_telnet_options(conn); - if(code) - return code; + result = check_telnet_options(conn); + if(result) + return result; #ifdef USE_WINSOCK /* ** This functionality only works with WinSock >= 2.0. So, ** make sure have it. */ - code = check_wsock2(data); - if(code) - return code; + result = check_wsock2(data); + if(result) + return result; /* OK, so we have WinSock 2.0. We need to dynamically */ /* load ws2_32.dll and get the function pointers we need. */ wsock2 = LoadLibrary(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 (%d)", ERRNO); return CURLE_FAILED_INIT; } /* Grab a pointer to WSACreateEvent */ - create_event_func = GetProcAddress(wsock2,"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 (%d)", ERRNO); FreeLibrary(wsock2); return CURLE_FAILED_INIT; } /* And WSACloseEvent */ - close_event_func = GetProcAddress(wsock2,"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 (%d)", ERRNO); FreeLibrary(wsock2); return CURLE_FAILED_INIT; } /* And WSAEventSelect */ - event_select_func = GetProcAddress(wsock2,"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 (%d)", ERRNO); FreeLibrary(wsock2); return CURLE_FAILED_INIT; } /* And WSAEnumNetworkEvents */ - enum_netevents_func = GetProcAddress(wsock2,"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 (%d)", ERRNO); FreeLibrary(wsock2); return CURLE_FAILED_INIT; } @@ -1386,7 +1380,7 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) /* First, create a sockets event object */ event_handle = (WSAEVENT)create_event_func(); if(event_handle == WSA_INVALID_EVENT) { - failf(data,"WSACreateEvent failed (%d)", SOCKERRNO); + failf(data, "WSACreateEvent failed (%d)", SOCKERRNO); FreeLibrary(wsock2); return CURLE_FAILED_INIT; } @@ -1427,29 +1421,30 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) case WAIT_TIMEOUT: { for(;;) { - if(obj_count == 1) { + if(data->set.is_fread_set) { /* read from user-supplied method */ - code = (int)conn->fread_func(buf, 1, BUFSIZE - 1, conn->fread_in); - if(code == CURL_READFUNC_ABORT) { + result = (int)data->set.fread_func(buf, 1, BUFSIZE - 1, + data->set.in); + if(result == CURL_READFUNC_ABORT) { keepon = FALSE; - code = CURLE_READ_ERROR; + result = CURLE_READ_ERROR; break; } - if(code == CURL_READFUNC_PAUSE) + if(result == CURL_READFUNC_PAUSE) break; - if(code == 0) /* no bytes */ + if(result == 0) /* no bytes */ break; - readfile_read = code; /* fall thru with number of bytes read */ + readfile_read = result; /* fall thru with number of bytes read */ } else { /* read from stdin */ if(!PeekNamedPipe(stdin_handle, NULL, 0, NULL, &readfile_read, NULL)) { keepon = FALSE; - code = CURLE_READ_ERROR; + result = CURLE_READ_ERROR; break; } @@ -1459,13 +1454,13 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer), &readfile_read, NULL)) { keepon = FALSE; - code = CURLE_READ_ERROR; + result = CURLE_READ_ERROR; break; } } - code = send_telnet_data(conn, buf, readfile_read); - if(code) { + result = send_telnet_data(conn, buf, readfile_read); + if(result) { keepon = FALSE; break; } @@ -1478,12 +1473,12 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer), &readfile_read, NULL)) { keepon = FALSE; - code = CURLE_READ_ERROR; + result = CURLE_READ_ERROR; break; } - code = send_telnet_data(conn, buf, readfile_read); - if(code) { + result = send_telnet_data(conn, buf, readfile_read); + if(result) { keepon = FALSE; break; } @@ -1495,20 +1490,20 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) events.lNetworkEvents = 0; if(SOCKET_ERROR == enum_netevents_func(sockfd, event_handle, &events)) { if((err = SOCKERRNO) != EINPROGRESS) { - infof(data,"WSAEnumNetworkEvents failed (%d)", err); + infof(data, "WSAEnumNetworkEvents failed (%d)", err); keepon = FALSE; - code = CURLE_READ_ERROR; + result = CURLE_READ_ERROR; } break; } if(events.lNetworkEvents & FD_READ) { /* read data from network */ - code = Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread); + result = Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread); /* read would've blocked. Loop again */ - if(code == CURLE_AGAIN) + if(result == CURLE_AGAIN) break; /* returned not-zero, this an error */ - else if(code) { + else if(result) { keepon = FALSE; break; } @@ -1519,8 +1514,8 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) break; } - code = telrcv(conn, (unsigned char *)buf, nread); - if(code) { + result = telrcv(conn, (unsigned char *) buf, nread); + if(result) { keepon = FALSE; break; } @@ -1544,7 +1539,7 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) now = Curl_tvnow(); if(Curl_tvdiff(now, conn->created) >= data->set.timeout) { failf(data, "Time-out"); - code = CURLE_OPERATION_TIMEDOUT; + result = CURLE_OPERATION_TIMEDOUT; keepon = FALSE; } } @@ -1552,7 +1547,7 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) /* We called WSACreateEvent, so call WSACloseEvent */ if(!close_event_func(event_handle)) { - infof(data,"WSACloseEvent failed (%d)", SOCKERRNO); + infof(data, "WSACloseEvent failed (%d)", SOCKERRNO); } /* "Forget" pointers into the library we're about to free */ @@ -1563,18 +1558,18 @@ 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 (%d)", ERRNO); #else pfd[0].fd = sockfd; pfd[0].events = POLLIN; - if(conn->fread_func != (curl_read_callback)fread) { + if(data->set.fread_func != (curl_read_callback)fread) { poll_cnt = 1; interval_ms = 100; /* poll user-supplied read function */ } else { /* really using fread, so infile is a FILE* */ - pfd[1].fd = fileno((FILE *)conn->fread_in); + pfd[1].fd = fileno((FILE *)data->set.in); pfd[1].events = POLLIN; poll_cnt = 2; interval_ms = 1 * 1000; @@ -1592,12 +1587,12 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) default: /* read! */ if(pfd[0].revents & POLLIN) { /* read data from network */ - code = Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread); + result = Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread); /* read would've blocked. Loop again */ - if(code == CURLE_AGAIN) + if(result == CURLE_AGAIN) break; /* returned not-zero, this an error */ - else if(code) { + else if(result) { keepon = FALSE; break; } @@ -1610,8 +1605,8 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) total_dl += nread; Curl_pgrsSetDownloadCounter(data, total_dl); - code = telrcv(conn, (unsigned char *)buf, nread); - if(code) { + result = telrcv(conn, (unsigned char *)buf, nread); + if(result) { keepon = FALSE; break; } @@ -1633,7 +1628,7 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) } else { /* read from user-supplied method */ - nread = (int)conn->fread_func(buf, 1, BUFSIZE - 1, conn->fread_in); + nread = (int)data->set.fread_func(buf, 1, BUFSIZE - 1, data->set.in); if(nread == CURL_READFUNC_ABORT) { keepon = FALSE; break; @@ -1643,8 +1638,8 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) } if(nread > 0) { - code = send_telnet_data(conn, buf, nread); - if(code) { + result = send_telnet_data(conn, buf, nread); + if(result) { keepon = FALSE; break; } @@ -1661,13 +1656,13 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) now = Curl_tvnow(); if(Curl_tvdiff(now, conn->created) >= data->set.timeout) { failf(data, "Time-out"); - code = CURLE_OPERATION_TIMEDOUT; + result = CURLE_OPERATION_TIMEDOUT; keepon = FALSE; } } if(Curl_pgrsUpdate(conn)) { - code = CURLE_ABORTED_BY_CALLBACK; + result = CURLE_ABORTED_BY_CALLBACK; break; } } @@ -1675,6 +1670,6 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) /* mark this as "no further transfer wanted" */ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); - return code; + return result; } #endif diff --git a/Utilities/cmcurl/lib/tftp.c b/Utilities/cmcurl/lib/tftp.c index e499c45..4c5796f 100644 --- a/Utilities/cmcurl/lib/tftp.c +++ b/Utilities/cmcurl/lib/tftp.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -57,14 +57,11 @@ #include "url.h" #include "rawstr.h" #include "speedcheck.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - -#include "curl_memory.h" +#include "curl_printf.h" #include "select.h" -/* The last #include file should be: */ +/* The last #include files should be: */ +#include "curl_memory.h" #include "memdebug.h" /* RFC2348 allows the block size to be negotiated */ @@ -148,8 +145,8 @@ typedef struct tftp_state_data { /* Forward declarations */ -static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event) ; -static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event) ; +static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event); +static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event); static CURLcode tftp_connect(struct connectdata *conn, bool *done); static CURLcode tftp_disconnect(struct connectdata *conn, bool dead_connection); @@ -221,7 +218,7 @@ static CURLcode tftp_set_timeouts(tftp_state_data_t *state) state->max_time = state->start_time+maxtime; /* Set per-block timeout to total */ - timeout = maxtime ; + timeout = maxtime; /* Average restart after 5 seconds */ state->retry_max = (int)timeout/5; @@ -411,38 +408,38 @@ static size_t tftp_option_add(tftp_state_data_t *state, size_t csize, if(( strlen(option) + csize + 1 ) > (size_t)state->blksize) return 0; strcpy(buf, option); - return( strlen(option) + 1 ); + return strlen(option) + 1; } static CURLcode tftp_connect_for_tx(tftp_state_data_t *state, tftp_event_t event) { - CURLcode res; + CURLcode result; #ifndef CURL_DISABLE_VERBOSE_STRINGS struct SessionHandle *data = state->conn->data; infof(data, "%s\n", "Connected for transmit"); #endif state->state = TFTP_STATE_TX; - res = tftp_set_timeouts(state); - if(res != CURLE_OK) - return(res); + result = tftp_set_timeouts(state); + if(result) + return result; return tftp_tx(state, event); } static CURLcode tftp_connect_for_rx(tftp_state_data_t *state, tftp_event_t event) { - CURLcode res; + CURLcode result; #ifndef CURL_DISABLE_VERBOSE_STRINGS struct SessionHandle *data = state->conn->data; infof(data, "%s\n", "Connected for receive"); #endif state->state = TFTP_STATE_RX; - res = tftp_set_timeouts(state); - if(res != CURLE_OK) - return(res); + result = tftp_set_timeouts(state); + if(result) + return result; return tftp_rx(state, event); } @@ -454,7 +451,7 @@ static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event) char *filename; char buf[64]; struct SessionHandle *data = state->conn->data; - CURLcode res = CURLE_OK; + CURLcode result = CURLE_OK; /* Set ascii mode if -B flag was used */ if(data->set.prefer_ascii) @@ -469,7 +466,7 @@ static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event) if(state->retries>state->retry_max) { state->error = TFTP_ERR_NORESPONSE; state->state = TFTP_STATE_FIN; - return res; + return result; } if(data->set.upload) { @@ -534,24 +531,24 @@ static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event) if(senddata != (ssize_t)sbytes) { failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO)); } - Curl_safefree(filename); + free(filename); break; case TFTP_EVENT_OACK: if(data->set.upload) { - res = tftp_connect_for_tx(state, event); + result = tftp_connect_for_tx(state, event); } else { - res = tftp_connect_for_rx(state, event); + result = tftp_connect_for_rx(state, event); } break; case TFTP_EVENT_ACK: /* Connected for transmit */ - res = tftp_connect_for_tx(state, event); + result = tftp_connect_for_tx(state, event); break; case TFTP_EVENT_DATA: /* Connected for receive */ - res = tftp_connect_for_rx(state, event); + result = tftp_connect_for_rx(state, event); break; case TFTP_EVENT_ERROR: @@ -562,7 +559,8 @@ static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event) failf(state->conn->data, "tftp_send_first: internal error"); break; } - return res; + + return result; } /* the next blocknum is x + 1 but it needs to wrap at an unsigned 16bit @@ -702,7 +700,7 @@ static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event) struct SessionHandle *data = state->conn->data; ssize_t sbytes; int rblock; - CURLcode res = CURLE_OK; + CURLcode result = CURLE_OK; struct SingleRequest *k = &data->req; switch(event) { @@ -728,7 +726,7 @@ static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event) if(state->retries>state->retry_max) { failf(data, "tftp_tx: giving up waiting for block %d ack", state->block); - res = CURLE_SEND_ERROR; + result = CURLE_SEND_ERROR; } else { /* Re-send the data packet */ @@ -739,10 +737,11 @@ static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event) /* Check all sbytes were sent */ if(sbytes<0) { failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO)); - res = CURLE_SEND_ERROR; + result = CURLE_SEND_ERROR; } } - return res; + + return result; } /* This is the expected packet. Reset the counters and send the next block */ @@ -759,11 +758,13 @@ static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event) state->state = TFTP_STATE_FIN; return CURLE_OK; } - res = Curl_fillreadbuffer(state->conn, state->blksize, &state->sbytes); - if(res) - return res; - sbytes = sendto(state->sockfd, (void *)state->spacket.data, - 4+state->sbytes, SEND_4TH_ARG, + + result = Curl_fillreadbuffer(state->conn, state->blksize, &state->sbytes); + if(result) + return result; + + sbytes = sendto(state->sockfd, (void *) state->spacket.data, + 4 + state->sbytes, SEND_4TH_ARG, (struct sockaddr *)&state->remote_addr, state->remote_addrlen); /* Check all sbytes were sent */ @@ -819,7 +820,7 @@ static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event) break; } - return res; + return result; } /********************************************************** @@ -831,48 +832,47 @@ static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event) **********************************************************/ static CURLcode tftp_translate_code(tftp_error_t error) { - CURLcode code = CURLE_OK; + CURLcode result = CURLE_OK; if(error != TFTP_ERR_NONE) { switch(error) { case TFTP_ERR_NOTFOUND: - code = CURLE_TFTP_NOTFOUND; + result = CURLE_TFTP_NOTFOUND; break; case TFTP_ERR_PERM: - code = CURLE_TFTP_PERM; + result = CURLE_TFTP_PERM; break; case TFTP_ERR_DISKFULL: - code = CURLE_REMOTE_DISK_FULL; + result = CURLE_REMOTE_DISK_FULL; break; case TFTP_ERR_UNDEF: case TFTP_ERR_ILLEGAL: - code = CURLE_TFTP_ILLEGAL; + result = CURLE_TFTP_ILLEGAL; break; case TFTP_ERR_UNKNOWNID: - code = CURLE_TFTP_UNKNOWNID; + result = CURLE_TFTP_UNKNOWNID; break; case TFTP_ERR_EXISTS: - code = CURLE_REMOTE_FILE_EXISTS; + result = CURLE_REMOTE_FILE_EXISTS; break; case TFTP_ERR_NOSUCHUSER: - code = CURLE_TFTP_NOSUCHUSER; + result = CURLE_TFTP_NOSUCHUSER; break; case TFTP_ERR_TIMEOUT: - code = CURLE_OPERATION_TIMEDOUT; + result = CURLE_OPERATION_TIMEDOUT; break; case TFTP_ERR_NORESPONSE: - code = CURLE_COULDNT_CONNECT; + result = CURLE_COULDNT_CONNECT; break; default: - code= CURLE_ABORTED_BY_CALLBACK; + result = CURLE_ABORTED_BY_CALLBACK; break; } } - else { - code = CURLE_OK; - } + else + result = CURLE_OK; - return(code); + return result; } /********************************************************** @@ -885,20 +885,21 @@ static CURLcode tftp_translate_code(tftp_error_t error) static CURLcode tftp_state_machine(tftp_state_data_t *state, tftp_event_t event) { - CURLcode res = CURLE_OK; + CURLcode result = CURLE_OK; struct SessionHandle *data = state->conn->data; + switch(state->state) { case TFTP_STATE_START: DEBUGF(infof(data, "TFTP_STATE_START\n")); - res = tftp_send_first(state, event); + result = tftp_send_first(state, event); break; case TFTP_STATE_RX: DEBUGF(infof(data, "TFTP_STATE_RX\n")); - res = tftp_rx(state, event); + result = tftp_rx(state, event); break; case TFTP_STATE_TX: DEBUGF(infof(data, "TFTP_STATE_TX\n")); - res = tftp_tx(state, event); + result = tftp_tx(state, event); break; case TFTP_STATE_FIN: infof(data, "%s\n", "TFTP finished"); @@ -906,10 +907,11 @@ static CURLcode tftp_state_machine(tftp_state_data_t *state, default: DEBUGF(infof(data, "STATE: %d\n", state->state)); failf(data, "%s", "Internal state machine error"); - res = CURLE_TFTP_ILLEGAL; + result = CURLE_TFTP_ILLEGAL; break; } - return res; + + return result; } /********************************************************** @@ -943,7 +945,6 @@ static CURLcode tftp_disconnect(struct connectdata *conn, bool dead_connection) **********************************************************/ static CURLcode tftp_connect(struct connectdata *conn, bool *done) { - CURLcode code; tftp_state_data_t *state; int blksize, rc; @@ -1017,8 +1018,8 @@ static CURLcode tftp_connect(struct connectdata *conn, bool *done) Curl_pgrsStartNow(conn->data); *done = TRUE; - code = CURLE_OK; - return(code); + + return CURLE_OK; } /********************************************************** @@ -1031,7 +1032,7 @@ static CURLcode tftp_connect(struct connectdata *conn, bool *done) static CURLcode tftp_done(struct connectdata *conn, CURLcode status, bool premature) { - CURLcode code = CURLE_OK; + CURLcode result = CURLE_OK; tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc; (void)status; /* unused */ @@ -1042,9 +1043,9 @@ static CURLcode tftp_done(struct connectdata *conn, CURLcode status, /* If we have encountered an error */ if(state) - code = tftp_translate_code(state->error); + result = tftp_translate_code(state->error); - return code; + return result; } /********************************************************** @@ -1208,8 +1209,8 @@ static CURLcode tftp_multi_statemach(struct connectdata *conn, bool *done) } else if(event != TFTP_EVENT_NONE) { result = tftp_state_machine(state, event); - if(result != CURLE_OK) - return(result); + if(result) + return result; *done = (state->state == TFTP_STATE_FIN) ? TRUE : FALSE; if(*done) /* Tell curl we're done */ @@ -1227,11 +1228,11 @@ static CURLcode tftp_multi_statemach(struct connectdata *conn, bool *done) } else if(rc != 0) { result = tftp_receive_packet(conn); - if(result != CURLE_OK) - return(result); + if(result) + return result; result = tftp_state_machine(state, state->event); - if(result != CURLE_OK) - return(result); + if(result) + return result; *done = (state->state == TFTP_STATE_FIN) ? TRUE : FALSE; if(*done) /* Tell curl we're done */ @@ -1286,8 +1287,8 @@ static CURLcode tftp_perform(struct connectdata *conn, bool *dophase_done) result = tftp_state_machine(state, TFTP_EVENT_INIT); - if(state->state == TFTP_STATE_FIN || result != CURLE_OK) - return(result); + if((state->state == TFTP_STATE_FIN) || result) + return result; tftp_multi_statemach(conn, dophase_done); @@ -1310,30 +1311,30 @@ static CURLcode tftp_perform(struct connectdata *conn, bool *dophase_done) static CURLcode tftp_do(struct connectdata *conn, bool *done) { - tftp_state_data_t *state; - CURLcode code; + tftp_state_data_t *state; + CURLcode result; *done = FALSE; if(!conn->proto.tftpc) { - code = tftp_connect(conn, done); - if(code) - return code; + result = tftp_connect(conn, done); + if(result) + return result; } state = (tftp_state_data_t *)conn->proto.tftpc; if(!state) return CURLE_BAD_CALLING_ORDER; - code = tftp_perform(conn, done); + result = tftp_perform(conn, done); /* If tftp_perform() returned an error, use that for return code. If it was OK, see if tftp_translate_code() has an error. */ - if(code == CURLE_OK) + if(!result) /* If we have encountered an internal tftp error, translate it. */ - code = tftp_translate_code(state->error); + result = tftp_translate_code(state->error); - return code; + return result; } static CURLcode tftp_setup_connection(struct connectdata * conn) diff --git a/Utilities/cmcurl/lib/timeval.c b/Utilities/cmcurl/lib/timeval.c index 2fd7201..45731ac 100644 --- a/Utilities/cmcurl/lib/timeval.c +++ b/Utilities/cmcurl/lib/timeval.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2008, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -32,9 +32,17 @@ struct timeval curlx_tvnow(void) ** increases monotonically and wraps once 49.7 days have elapsed. */ struct timeval now; +#if !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_VISTA) || \ + (_WIN32_WINNT < _WIN32_WINNT_VISTA) DWORD milliseconds = GetTickCount(); now.tv_sec = milliseconds / 1000; now.tv_usec = (milliseconds % 1000) * 1000; +#else + ULONGLONG milliseconds = GetTickCount64(); + now.tv_sec = (long) (milliseconds / 1000); + now.tv_usec = (long) (milliseconds % 1000) * 1000; +#endif + return now; } @@ -110,7 +118,7 @@ struct timeval curlx_tvnow(void) long curlx_tvdiff(struct timeval newer, struct timeval older) { return (newer.tv_sec-older.tv_sec)*1000+ - (newer.tv_usec-older.tv_usec)/1000; + (long)(newer.tv_usec-older.tv_usec)/1000; } /* diff --git a/Utilities/cmcurl/lib/transfer.c b/Utilities/cmcurl/lib/transfer.c index dc817a6..718139b 100644 --- a/Utilities/cmcurl/lib/transfer.c +++ b/Utilities/cmcurl/lib/transfer.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -75,16 +75,14 @@ #include "curl_ntlm.h" #include "http_negotiate.h" #include "share.h" -#include "curl_memory.h" #include "select.h" #include "multiif.h" #include "connect.h" #include "non-ascii.h" +#include "curl_printf.h" -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - -/* The last #include file should be: */ +/* The last #include files should be: */ +#include "curl_memory.h" #include "memdebug.h" /* @@ -117,8 +115,8 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp) /* this function returns a size_t, so we typecast to int to prevent warnings with picky compilers */ - nread = (int)conn->fread_func(data->req.upload_fromhere, 1, - buffersize, conn->fread_in); + nread = (int)data->set.fread_func(data->req.upload_fromhere, 1, + buffersize, data->set.in); if(nread == CURL_READFUNC_ABORT) { failf(data, "operation aborted by callback"); @@ -203,7 +201,7 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp) strlen(endofline_network)); #ifdef CURL_DOES_CONVERSIONS - CURLcode res; + CURLcode result; int length; if(data->set.prefer_ascii) { /* translate the protocol and data */ @@ -213,10 +211,10 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp) /* just translate the protocol portion */ length = strlen(hexbuffer); } - res = Curl_convert_to_network(data, data->req.upload_fromhere, length); + result = Curl_convert_to_network(data, data->req.upload_fromhere, length); /* Curl_convert_to_network calls failf if unsuccessful */ - if(res) - return(res); + if(result) + return result; #endif /* CURL_DOES_CONVERSIONS */ if((nread - hexlen) == 0) @@ -227,11 +225,11 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp) } #ifdef CURL_DOES_CONVERSIONS else if((data->set.prefer_ascii) && (!sending_http_headers)) { - CURLcode res; - res = Curl_convert_to_network(data, data->req.upload_fromhere, nread); + CURLcode result; + result = Curl_convert_to_network(data, data->req.upload_fromhere, nread); /* Curl_convert_to_network calls failf if unsuccessful */ - if(res != CURLE_OK) - return(res); + if(result) + return result; } #endif /* CURL_DOES_CONVERSIONS */ @@ -319,8 +317,7 @@ static int data_pending(const struct connectdata *conn) TRUE. The thing is if we read everything, then http2_recv won't be called and we cannot signal the HTTP/2 stream has closed. As a workaround, we return nonzero here to call http2_recv. */ - ((conn->handler->protocol&PROTO_FAMILY_HTTP) && conn->httpversion == 20 && - conn->proto.httpc.closed); + ((conn->handler->protocol&PROTO_FAMILY_HTTP) && conn->httpversion == 20); #else Curl_ssl_data_pending(conn, FIRSTSOCKET); #endif @@ -435,6 +432,7 @@ static CURLcode readwrite_data(struct SessionHandle *data, else { /* read nothing but since we wanted nothing we consider this an OK situation to proceed from */ + DEBUGF(infof(data, "readwrite_data: we're done!\n")); nread = 0; } @@ -496,7 +494,7 @@ static CURLcode readwrite_data(struct SessionHandle *data, /* We've stopped dealing with input, get out of the do-while loop */ if(nread > 0) { - if(Curl_multi_pipeline_enabled(conn->data->multi)) { + if(Curl_pipeline_wanted(conn->data->multi, CURLPIPE_HTTP1)) { infof(data, "Rewinding stream by : %zd" " bytes on url %s (zero-length body)\n", @@ -547,6 +545,18 @@ static CURLcode readwrite_data(struct SessionHandle *data, if(data->state.resume_from && !k->content_range && (data->set.httpreq==HTTPREQ_GET) && !k->ignorebody) { + + if(k->size == data->state.resume_from) { + /* The resume point is at the end of file, consider this fine + even if it doesn't allow resume from here. */ + infof(data, "The entire document is already downloaded"); + connclose(conn, "already downloaded"); + /* Abort download */ + k->keepon &= ~KEEP_RECV; + *done = TRUE; + return CURLE_OK; + } + /* we wanted to resume a download, although the server doesn't * seem to support this and we did this with a GET (if it * wasn't a GET we did a POST or PUT resume) */ @@ -629,7 +639,7 @@ static CURLcode readwrite_data(struct SessionHandle *data, if(dataleft != 0) { infof(conn->data, "Leftovers after chunking: %zu bytes\n", dataleft); - if(Curl_multi_pipeline_enabled(conn->data->multi)) { + if(Curl_pipeline_wanted(conn->data->multi, CURLPIPE_HTTP1)) { /* only attempt the rewind if we truly are pipelining */ infof(conn->data, "Rewinding %zu bytes\n",dataleft); read_rewind(conn, dataleft); @@ -652,7 +662,7 @@ static CURLcode readwrite_data(struct SessionHandle *data, excess = (size_t)(k->bytecount + nread - k->maxdownload); if(excess > 0 && !k->ignorebody) { - if(Curl_multi_pipeline_enabled(conn->data->multi)) { + if(Curl_pipeline_wanted(conn->data->multi, CURLPIPE_HTTP1)) { /* The 'excess' amount below can't be more than BUFSIZE which always will fit in a size_t */ infof(data, @@ -746,7 +756,6 @@ static CURLcode readwrite_data(struct SessionHandle *data, result = Curl_unencode_gzip_write(conn, k, nread); break; - case COMPRESS: default: failf (data, "Unrecognized content encoding type. " "libcurl understands `identity', `deflate' and `gzip' " @@ -818,13 +827,6 @@ static CURLcode readwrite_upload(struct SessionHandle *data, *didwhat |= KEEP_SEND; - /* - * We loop here to do the READ and SEND loop until we run out of - * data to send or until we get EWOULDBLOCK back - * - * FIXME: above comment is misleading. Currently no looping is - * actually done in do-while loop below. - */ do { /* only read more data if there's no upload data already @@ -891,15 +893,6 @@ static CURLcode readwrite_upload(struct SessionHandle *data, /* store number of bytes available for upload */ data->req.upload_present = nread; -#ifndef CURL_DISABLE_SMTP - if(conn->handler->protocol & PROTO_FAMILY_SMTP) { - result = Curl_smtp_escape_eob(conn, nread); - if(result) - return result; - } - else -#endif /* CURL_DISABLE_SMTP */ - /* convert LF to CRLF if so asked */ if((!sending_http_headers) && ( #ifdef CURL_DO_LINEEND_CONV @@ -907,12 +900,16 @@ static CURLcode readwrite_upload(struct SessionHandle *data, (data->set.prefer_ascii) || #endif (data->set.crlf))) { - if(data->state.scratch == NULL) - data->state.scratch = malloc(2*BUFSIZE); - if(data->state.scratch == NULL) { - failf (data, "Failed to alloc scratch buffer!"); - return CURLE_OUT_OF_MEMORY; + /* Do we need to allocate a scratch buffer? */ + if(!data->state.scratch) { + data->state.scratch = malloc(2 * BUFSIZE); + if(!data->state.scratch) { + failf(data, "Failed to alloc scratch buffer!"); + + return CURLE_OUT_OF_MEMORY; + } } + /* * ASCII/EBCDIC Note: This is presumably a text (not binary) * transfer so the data should already be in ASCII. @@ -932,6 +929,7 @@ static CURLcode readwrite_upload(struct SessionHandle *data, else data->state.scratch[si] = data->req.upload_fromhere[i]; } + if(si != nread) { /* only perform the special operation if we really did replace anything */ @@ -944,6 +942,14 @@ static CURLcode readwrite_upload(struct SessionHandle *data, data->req.upload_present = nread; } } + +#ifndef CURL_DISABLE_SMTP + if(conn->handler->protocol & PROTO_FAMILY_SMTP) { + result = Curl_smtp_escape_eob(conn, nread); + if(result) + return result; + } +#endif /* CURL_DISABLE_SMTP */ } /* if 0 == data->req.upload_present */ else { /* We have a partial buffer left from a previous "round". Use @@ -1006,9 +1012,9 @@ static CURLcode readwrite_upload(struct SessionHandle *data, * be read and written to/from the connection. */ CURLcode Curl_readwrite(struct connectdata *conn, + struct SessionHandle *data, bool *done) { - struct SessionHandle *data = conn->data; struct SingleRequest *k = &data->req; CURLcode result; int didwhat=0; @@ -1032,6 +1038,11 @@ CURLcode Curl_readwrite(struct connectdata *conn, else fd_write = CURL_SOCKET_BAD; + if(conn->data->state.drain) { + select_res |= CURL_CSELECT_IN; + DEBUGF(infof(data, "Curl_readwrite: forcibly told to drain data\n")); + } + if(!select_res) /* Call for select()/poll() only, if read/write/error status is not known. */ select_res = Curl_socket_ready(fd_read, fd_write, 0); @@ -1202,10 +1213,10 @@ int Curl_single_getsock(const struct connectdata *conn, if((data->req.keepon & KEEP_SENDBITS) == KEEP_SEND) { if((conn->sockfd != conn->writesockfd) || - !(data->req.keepon & KEEP_RECV)) { - /* only if they are not the same socket or we didn't have a readable + bitmap == GETSOCK_BLANK) { + /* only if they are not the same socket and we have a readable one, we increase index */ - if(data->req.keepon & KEEP_RECV) + if(bitmap != GETSOCK_BLANK) sockindex++; /* increase index if we need two entries */ DEBUGASSERT(conn->writesockfd != CURL_SOCKET_BAD); @@ -1256,7 +1267,7 @@ long Curl_sleep_time(curl_off_t rate_bps, curl_off_t cur_rate_bps, * the next packet at the adjusted rate. We should wait * longer when using larger packets, for instance. */ - rv = ((curl_off_t)((pkt_size * 8) * 1000) / rate_bps); + rv = ((curl_off_t)(pkt_size * 1000) / rate_bps); /* Catch rounding errors and always slow down at least 1ms if * we are running too fast. @@ -1278,7 +1289,7 @@ long Curl_sleep_time(curl_off_t rate_bps, curl_off_t cur_rate_bps, */ CURLcode Curl_pretransfer(struct SessionHandle *data) { - CURLcode res; + CURLcode result; if(!data->change.url) { /* we can't do anything without URL */ failf(data, "No URL set!"); @@ -1288,32 +1299,35 @@ CURLcode Curl_pretransfer(struct SessionHandle *data) /* 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 before any transfer takes place. */ - res = Curl_ssl_initsessions(data, data->set.ssl.max_ssl_sessions); - if(res) - return res; + result = Curl_ssl_initsessions(data, data->set.ssl.max_ssl_sessions); + if(result) + return result; 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 */ - data->state.ssl_connect_retry = FALSE; - data->state.authproblem = FALSE; data->state.authhost.want = data->set.httpauth; data->state.authproxy.want = data->set.proxyauth; Curl_safefree(data->info.wouldredirect); data->info.wouldredirect = NULL; + if(data->set.httpreq == HTTPREQ_PUT) + data->state.infilesize = data->set.filesize; + else + data->state.infilesize = data->set.postfieldsize; + /* If there is a list of cookie files to read, do it now! */ if(data->change.cookielist) Curl_cookie_loadfiles(data); /* If there is a list of host pairs to deal with */ if(data->change.resolve) - res = Curl_loadhostpairs(data); + result = Curl_loadhostpairs(data); - if(!res) { + if(!result) { /* Allow data->set.use_port to set which port to use. This needs to be * disabled for example when we follow Location: headers to URLs using * different ports! */ @@ -1328,6 +1342,7 @@ CURLcode Curl_pretransfer(struct SessionHandle *data) #endif Curl_initinfo(data); /* reset session-specific information "variables" */ + Curl_pgrsResetTimesSizes(data); Curl_pgrsStartNow(data); if(data->set.timeout) @@ -1343,7 +1358,7 @@ CURLcode Curl_pretransfer(struct SessionHandle *data) data->state.authproxy.picked &= data->state.authproxy.want; } - return res; + return result; } /* @@ -1619,7 +1634,7 @@ CURLcode Curl_follow(struct SessionHandle *data, if(type == FOLLOW_REDIR) { if((data->set.maxredirs != -1) && (data->set.followlocation >= data->set.maxredirs)) { - failf(data,"Maximum (%ld) redirects followed", data->set.maxredirs); + failf(data, "Maximum (%ld) redirects followed", data->set.maxredirs); return CURLE_TOO_MANY_REDIRECTS; } @@ -1828,13 +1843,13 @@ Curl_reconnect_request(struct connectdata **connp) * (again). Slight Lack of feedback in the report, but I don't think this * extra check can do much harm. */ - if((CURLE_OK == result) || (CURLE_SEND_ERROR == result)) { + if(!result || (CURLE_SEND_ERROR == result)) { bool async; bool protocol_done = TRUE; /* Now, redo the connect and get a new connection */ result = Curl_connect(data, connp, &async, &protocol_done); - if(CURLE_OK == result) { + if(!result) { /* We have connected or sent away a name resolve query fine */ conn = *connp; /* setup conn to again point to something nice */ @@ -1872,12 +1887,10 @@ CURLcode Curl_retry_request(struct connectdata *conn, !(conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_RTSP))) return CURLE_OK; - if(/* workaround for broken TLS servers */ data->state.ssl_connect_retry || - ((data->req.bytecount + - data->req.headerbytecount == 0) && - conn->bits.reuse && - !data->set.opt_no_body && - data->set.rtspreq != RTSPREQ_RECEIVE)) { + if((data->req.bytecount + data->req.headerbytecount == 0) && + conn->bits.reuse && + !data->set.opt_no_body && + (data->set.rtspreq != RTSPREQ_RECEIVE)) { /* We got no data, we attempted to re-use a connection and yet we want a "body". This might happen if the connection was left alive when we were done using it before, but that was closed when we wanted to read from diff --git a/Utilities/cmcurl/lib/transfer.h b/Utilities/cmcurl/lib/transfer.h index ad4a3ac..316aeae 100644 --- a/Utilities/cmcurl/lib/transfer.h +++ b/Utilities/cmcurl/lib/transfer.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -40,7 +40,8 @@ CURLcode Curl_follow(struct SessionHandle *data, char *newurl, followtype type); -CURLcode Curl_readwrite(struct connectdata *conn, bool *done); +CURLcode Curl_readwrite(struct connectdata *conn, + struct SessionHandle *data, bool *done); int Curl_single_getsock(const struct connectdata *conn, curl_socket_t *socks, int numsocks); diff --git a/Utilities/cmcurl/lib/url.c b/Utilities/cmcurl/lib/url.c index 67126ab..406c1f0 100644 --- a/Utilities/cmcurl/lib/url.c +++ b/Utilities/cmcurl/lib/url.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -47,6 +47,10 @@ #include <inet.h> #endif +#ifdef HAVE_SYS_UN_H +#include <sys/un.h> +#endif + #ifndef HAVE_SOCKET #error "We can't compile without socket() support!" #endif @@ -120,15 +124,12 @@ int curl_win32_idn_to_ascii(const char *in, char **out); #include "curl_rtmp.h" #include "gopher.h" #include "http_proxy.h" -#include "bundles.h" #include "conncache.h" #include "multihandle.h" #include "pipeline.h" #include "dotdot.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - +#include "strdup.h" +#include "curl_printf.h" #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" @@ -141,7 +142,6 @@ find_oldest_idle_connection_in_bundle(struct SessionHandle *data, struct connectbundle *bundle); static void conn_free(struct connectdata *conn); static void signalPipeClose(struct curl_llist *pipeline, bool pipe_broke); -static CURLcode do_init(struct connectdata *conn); static CURLcode parse_url_login(struct SessionHandle *data, struct connectdata *conn, char **userptr, char **passwdptr, @@ -215,6 +215,15 @@ static const struct Curl_handler * const protocols[] = { #endif #endif +#if !defined(CURL_DISABLE_SMB) && defined(USE_NTLM) && \ + (CURL_SIZEOF_CURL_OFF_T > 4) && \ + (!defined(USE_WINDOWS_SSPI) || defined(USE_WIN32_CRYPTO)) + &Curl_handler_smb, +#ifdef USE_SSL + &Curl_handler_smbs, +#endif +#endif + #ifndef CURL_DISABLE_SMTP &Curl_handler_smtp, #ifdef USE_SSL @@ -270,8 +279,9 @@ void Curl_freeset(struct SessionHandle *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]); + } if(data->change.referer_alloc) { Curl_safefree(data->change.referer); @@ -345,7 +355,7 @@ static CURLcode setstropt_userpwd(char *option, char **userp, char **passwdp) CURLcode Curl_dupset(struct SessionHandle *dst, struct SessionHandle *src) { - CURLcode r = CURLE_OK; + CURLcode result = CURLE_OK; enum dupstring i; /* Copy src->set into dst->set first, then deal with the strings @@ -356,14 +366,25 @@ CURLcode Curl_dupset(struct SessionHandle *dst, struct SessionHandle *src) memset(dst->set.str, 0, STRING_LAST * sizeof(char *)); /* duplicate all strings */ - for(i=(enum dupstring)0; i< STRING_LAST; i++) { - r = setstropt(&dst->set.str[i], src->set.str[i]); - if(r != CURLE_OK) - break; + for(i=(enum dupstring)0; i< STRING_LASTZEROTERMINATED; i++) { + result = setstropt(&dst->set.str[i], src->set.str[i]); + if(result) + return result; + } + + /* duplicate memory areas pointed to */ + i = STRING_COPYPOSTFIELDS; + if(src->set.postfieldsize && src->set.str[i]) { + /* postfieldsize is curl_off_t, Curl_memdup() takes a size_t ... */ + dst->set.str[i] = Curl_memdup(src->set.str[i], + curlx_sotouz(src->set.postfieldsize)); + if(!dst->set.str[i]) + return CURLE_OUT_OF_MEMORY; + /* point to the new copy */ + dst->set.postfields = dst->set.str[i]; } - /* If a failure occurred, freeing has to be performed externally. */ - return r; + return CURLE_OK; } /* @@ -425,10 +446,8 @@ CURLcode Curl_close(struct SessionHandle *data) Curl_ssl_free_certinfo(data); /* Cleanup possible redirect junk */ - if(data->req.newurl) { - free(data->req.newurl); - data->req.newurl = NULL; - } + free(data->req.newurl); + data->req.newurl = NULL; if(data->change.referer_alloc) { Curl_safefree(data->change.referer); @@ -474,7 +493,7 @@ CURLcode Curl_close(struct SessionHandle *data) */ CURLcode Curl_init_userdefined(struct UserDefined *set) { - CURLcode res = CURLE_OK; + CURLcode result = CURLE_OK; set->out = stdout; /* default output to stdout */ set->in = stdin; /* default input from stdin */ @@ -540,8 +559,9 @@ CURLcode Curl_init_userdefined(struct UserDefined *set) define since we internally only use the lower 16 bits for the passed in bitmask to not conflict with the private bits */ set->allowed_protocols = CURLPROTO_ALL; - set->redir_protocols = - CURLPROTO_ALL & ~(CURLPROTO_FILE|CURLPROTO_SCP); /* not FILE or SCP */ + set->redir_protocols = CURLPROTO_ALL & /* All except FILE, SCP and SMB */ + ~(CURLPROTO_FILE | CURLPROTO_SCP | CURLPROTO_SMB | + CURLPROTO_SMBS); #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) /* @@ -550,17 +570,34 @@ CURLcode Curl_init_userdefined(struct UserDefined *set) */ set->socks5_gssapi_nec = FALSE; /* set default GSS-API service name */ - res = setstropt(&set->str[STRING_SOCKS5_GSSAPI_SERVICE], - (char *) CURL_DEFAULT_SOCKS5_GSSAPI_SERVICE); - if(res != CURLE_OK) - return res; + result = setstropt(&set->str[STRING_SOCKS5_GSSAPI_SERVICE], + (char *) CURL_DEFAULT_SOCKS5_GSSAPI_SERVICE); + if(result) + return result; + + /* set default negotiate proxy service name */ + result = setstropt(&set->str[STRING_PROXY_SERVICE_NAME], + (char *) CURL_DEFAULT_PROXY_SERVICE_NAME); + if(result) + return result; + + /* set default negotiate service name */ + result = setstropt(&set->str[STRING_SERVICE_NAME], + (char *) CURL_DEFAULT_SERVICE_NAME); + if(result) + return result; #endif /* This is our preferred CA cert bundle/path since install time */ #if defined(CURL_CA_BUNDLE) - res = setstropt(&set->str[STRING_SSL_CAFILE], (char *) CURL_CA_BUNDLE); -#elif defined(CURL_CA_PATH) - res = setstropt(&set->str[STRING_SSL_CAPATH], (char *) CURL_CA_PATH); + result = setstropt(&set->str[STRING_SSL_CAFILE], (char *) CURL_CA_BUNDLE); + if(result) + return result; +#endif +#if defined(CURL_CA_PATH) + result = setstropt(&set->str[STRING_SSL_CAPATH], (char *) CURL_CA_PATH); + if(result) + return result; #endif set->wildcardmatch = FALSE; @@ -578,7 +615,8 @@ CURLcode Curl_init_userdefined(struct UserDefined *set) set->ssl_enable_alpn = TRUE; set->expect_100_timeout = 1000L; /* Wait for a second by default. */ - return res; + set->sep_headers = TRUE; /* separated header lists by default */ + return result; } /** @@ -591,9 +629,8 @@ CURLcode Curl_init_userdefined(struct UserDefined *set) CURLcode Curl_open(struct SessionHandle **curl) { - CURLcode res = CURLE_OK; + CURLcode result; struct SessionHandle *data; - CURLcode status; /* Very simple start-up: alloc the struct, init it with zeroes and return */ data = calloc(1, sizeof(struct SessionHandle)); @@ -605,11 +642,11 @@ CURLcode Curl_open(struct SessionHandle **curl) data->magic = CURLEASY_MAGIC_NUMBER; - status = Curl_resolver_init(&data->state.resolver); - if(status) { + result = Curl_resolver_init(&data->state.resolver); + if(result) { DEBUGF(fprintf(stderr, "Error: resolver_init failed\n")); free(data); - return status; + return result; } /* We do some initial setup here, all those fields that can't be just 0 */ @@ -617,10 +654,10 @@ CURLcode Curl_open(struct SessionHandle **curl) data->state.headerbuff = malloc(HEADERSIZE); if(!data->state.headerbuff) { DEBUGF(fprintf(stderr, "Error: malloc of headerbuff failed\n")); - res = CURLE_OUT_OF_MEMORY; + result = CURLE_OUT_OF_MEMORY; } else { - res = Curl_init_userdefined(&data->set); + result = Curl_init_userdefined(&data->set); data->state.headersize=HEADERSIZE; @@ -638,10 +675,9 @@ CURLcode Curl_open(struct SessionHandle **curl) data->set.maxconnects = DEFAULT_CONNCACHE_SIZE; /* for easy handles */ } - if(res) { + if(result) { Curl_resolver_cleanup(data->state.resolver); - if(data->state.headerbuff) - free(data->state.headerbuff); + free(data->state.headerbuff); Curl_freeset(data); free(data); data = NULL; @@ -649,7 +685,7 @@ CURLcode Curl_open(struct SessionHandle **curl) else *curl = data; - return res; + return result; } CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, @@ -744,7 +780,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, break; case CURLOPT_FAILONERROR: /* - * Don't output the >=300 error code HTML-page, but instead only + * Don't output the >=400 error code HTML-page, but instead only * return error. */ data->set.http_fail_on_error = (0 != va_arg(param, long))?TRUE:FALSE; @@ -867,7 +903,11 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * Set explicit SSL version to try to connect with, as some SSL * implementations are lame. */ +#ifdef USE_SSL data->set.ssl.version = va_arg(param, long); +#else + result = CURLE_UNKNOWN_OPTION; +#endif break; #ifndef CURL_DISABLE_HTTP @@ -1139,6 +1179,8 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* * Set cookie file name to dump all cookies to when we're done. */ + { + struct CookieInfo *newcookies; result = setstropt(&data->set.str[STRING_COOKIEJAR], va_arg(param, char *)); @@ -1146,8 +1188,12 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * Activate the cookie parser. This may or may not already * have been made. */ - data->cookies = Curl_cookie_init(data, NULL, data->cookies, - data->set.cookiesession); + newcookies = Curl_cookie_init(data, NULL, data->cookies, + data->set.cookiesession); + if(!newcookies) + result = CURLE_OUT_OF_MEMORY; + data->cookies = newcookies; + } break; case CURLOPT_COOKIESESSION: @@ -1191,14 +1237,20 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* flush cookies to file, takes care of the locking */ Curl_flush_cookies(data, 0); } + else if(Curl_raw_equal(argptr, "RELOAD")) { + /* reload cookies from file */ + Curl_cookie_loadfiles(data); + break; + } else { if(!data->cookies) /* if cookie engine was not running, activate it */ data->cookies = Curl_cookie_init(data, NULL, NULL, TRUE); argptr = strdup(argptr); - if(!argptr) { + if(!argptr || !data->cookies) { result = CURLE_OUT_OF_MEMORY; + free(argptr); } else { Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); @@ -1431,12 +1483,29 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, va_arg(param, char *)); break; + case CURLOPT_PROXY_SERVICE_NAME: + /* + * Set negotiate proxy service name + */ + result = setstropt(&data->set.str[STRING_PROXY_SERVICE_NAME], + va_arg(param, char *)); + break; + case CURLOPT_SOCKS5_GSSAPI_NEC: /* * set flag for nec socks5 support */ data->set.socks5_gssapi_nec = (0 != va_arg(param, long))?TRUE:FALSE; break; + + case CURLOPT_SERVICE_NAME: + /* + * Set negotiate service identity + */ + result = setstropt(&data->set.str[STRING_SERVICE_NAME], + va_arg(param, char *)); + break; + #endif case CURLOPT_HEADERDATA: @@ -1959,30 +2028,63 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, data->set.ssl.verifyhost = (0 != arg)?TRUE:FALSE; break; -#ifdef USE_SSLEAY - /* since these two options are only possible to use on an OpenSSL- - powered libcurl we #ifdef them on this condition so that libcurls - built against other SSL libs will return a proper error when trying - to set this option! */ + case CURLOPT_SSL_VERIFYSTATUS: + /* + * Enable certificate status verifying. + */ + if(!Curl_ssl_cert_status_request()) { + result = CURLE_NOT_BUILT_IN; + break; + } + + data->set.ssl.verifystatus = (0 != va_arg(param, long))?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; +#endif 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 *); - break; +#else + result = CURLE_NOT_BUILT_IN; #endif -#if defined(USE_SSLEAY) || defined(USE_QSOSSL) || defined(USE_GSKIT) || \ - defined(USE_NSS) + break; + case CURLOPT_SSL_FALSESTART: + /* + * Enable TLS false start. + */ + if(!Curl_ssl_false_start()) { + result = CURLE_NOT_BUILT_IN; + break; + } + + 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; - break; +#else + result = CURLE_NOT_BUILT_IN; #endif + break; + case CURLOPT_PINNEDPUBLICKEY: + /* + * 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], + va_arg(param, char *)); + break; case CURLOPT_CAINFO: /* * Set CA info for SSL connection. Specify file name of the CA certificate @@ -1991,6 +2093,7 @@ CURLcode Curl_setopt(struct SessionHandle *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. @@ -1998,6 +2101,9 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* This does not work on windows. */ result = setstropt(&data->set.str[STRING_SSL_CAPATH], va_arg(param, char *)); +#else + result = CURLE_NOT_BUILT_IN; +#endif break; case CURLOPT_CRLFILE: /* @@ -2079,16 +2185,15 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, data->share->dirty++; - if(data->share->hostcache) { + if(data->share->specifier & (1<< CURL_LOCK_DATA_DNS)) { /* use shared host cache */ - data->dns.hostcache = data->share->hostcache; + data->dns.hostcache = &data->share->hostcache; data->dns.hostcachetype = HCACHE_SHARED; } #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) if(data->share->cookies) { /* use shared cookie list, first free own one if any */ - if(data->cookies) - Curl_cookie_cleanup(data->cookies); + Curl_cookie_cleanup(data->cookies); /* enable cookies since we now use a share that uses cookies! */ data->cookies = data->share->cookies; } @@ -2129,7 +2234,8 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, case CURLOPT_SSL_OPTIONS: arg = va_arg(param, long); - data->set.ssl_enable_beast = arg&CURLSSLOPT_ALLOW_BEAST?TRUE:FALSE; + data->set.ssl_enable_beast = !!(arg & CURLSSLOPT_ALLOW_BEAST); + data->set.ssl_no_revoke = !!(arg & CURLSSLOPT_NO_REVOKE); break; #endif @@ -2316,7 +2422,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * know that an unsigned int will always hold the value so we blindly * typecast to this type */ - data->set.scope = curlx_sltoui(va_arg(param, long)); + data->set.scope_id = curlx_sltoui(va_arg(param, long)); break; case CURLOPT_PROTOCOLS: @@ -2533,6 +2639,19 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, data->set.ssl_enable_alpn = (0 != va_arg(param, long))?TRUE:FALSE; break; +#ifdef USE_UNIX_SOCKETS + case CURLOPT_UNIX_SOCKET_PATH: + result = setstropt(&data->set.str[STRING_UNIX_SOCKET_PATH], + va_arg(param, char *)); + break; +#endif + + case CURLOPT_PATH_AS_IS: + data->set.path_as_is = (0 != va_arg(param, long))?TRUE:FALSE; + break; + case CURLOPT_PIPEWAIT: + data->set.pipewait = (0 != va_arg(param, long))?TRUE:FALSE; + break; default: /* unknown tag and its companion, just ignore: */ result = CURLE_UNKNOWN_OPTION; @@ -2565,7 +2684,8 @@ static void conn_free(struct connectdata *conn) if(CURL_SOCKET_BAD != conn->tempsock[1]) Curl_closesocket(conn, conn->tempsock[1]); -#if defined(USE_NTLM) && defined(NTLM_WB_ENABLED) +#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \ + defined(NTLM_WB_ENABLED) Curl_ntlm_wb_cleanup(conn); #endif @@ -2631,8 +2751,10 @@ CURLcode Curl_disconnect(struct connectdata *conn, bool dead_connection) Curl_hostcache_prune(data); /* kill old DNS cache entries */ +#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) /* Cleanup NTLM connection-related data */ Curl_http_ntlm_cleanup(conn); +#endif if(conn->handler->disconnect) /* This is set if protocol-specific cleanups should be made */ @@ -2655,16 +2777,15 @@ CURLcode Curl_disconnect(struct connectdata *conn, bool dead_connection) free(conn->host.encalloc); /* encoded host name buffer, must be freed with idn_free() since this was allocated by curl_win32_idn_to_ascii */ - if(conn->proxy.encalloc) - free(conn->proxy.encalloc); /* encoded proxy name buffer, must be freed - with idn_free() since this was allocated by - curl_win32_idn_to_ascii */ + free(conn->proxy.encalloc); /* encoded proxy name buffer, must be freed + with idn_free() since this was allocated by + curl_win32_idn_to_ascii */ #endif Curl_ssl_close(conn, FIRSTSOCKET); /* Indicate to all handles on the pipe that we're dead */ - if(Curl_multi_pipeline_enabled(data->multi)) { + if(Curl_pipeline_wanted(data->multi, CURLPIPE_ANY)) { signalPipeClose(conn->send_pipe, TRUE); signalPipeClose(conn->recv_pipe, TRUE); } @@ -2692,32 +2813,31 @@ static bool SocketIsDead(curl_socket_t sock) return ret_val; } +/* + * IsPipeliningPossible() returns TRUE if the options set would allow + * pipelining/multiplexing and the connection is using a HTTP protocol. + */ static bool IsPipeliningPossible(const struct SessionHandle *handle, const struct connectdata *conn) { - if((conn->handler->protocol & PROTO_FAMILY_HTTP) && - Curl_multi_pipeline_enabled(handle->multi) && - (handle->set.httpreq == HTTPREQ_GET || - handle->set.httpreq == HTTPREQ_HEAD) && - handle->set.httpversion != CURL_HTTP_VERSION_1_0) - return TRUE; + /* If a HTTP protocol and pipelining is enabled */ + if(conn->handler->protocol & PROTO_FAMILY_HTTP) { + + if(Curl_pipeline_wanted(handle->multi, CURLPIPE_HTTP1) && + (handle->set.httpversion != CURL_HTTP_VERSION_1_0) && + (handle->set.httpreq == HTTPREQ_GET || + handle->set.httpreq == HTTPREQ_HEAD)) + /* didn't ask for HTTP/1.0 and a GET or HEAD */ + return TRUE; + if(Curl_pipeline_wanted(handle->multi, CURLPIPE_MULTIPLEX) && + (handle->set.httpversion == CURL_HTTP_VERSION_2_0)) + /* allows HTTP/2 */ + return TRUE; + } return FALSE; } -bool Curl_isPipeliningEnabled(const struct SessionHandle *handle) -{ - return Curl_multi_pipeline_enabled(handle->multi); -} - -CURLcode Curl_addHandleToPipeline(struct SessionHandle *data, - struct curl_llist *pipeline) -{ - if(!Curl_llist_insert_next(pipeline, pipeline->tail, data)) - return CURLE_OUT_OF_MEMORY; - return CURLE_OK; -} - int Curl_removeHandleFromPipeline(struct SessionHandle *handle, struct curl_llist *pipeline) { @@ -2765,15 +2885,14 @@ void Curl_getoff_all_pipelines(struct SessionHandle *data, struct connectdata *conn) { bool recv_head = (conn->readchannel_inuse && - (gethandleathead(conn->recv_pipe) == data)) ? TRUE : FALSE; - + Curl_recvpipe_head(data, conn)); bool send_head = (conn->writechannel_inuse && - (gethandleathead(conn->send_pipe) == data)) ? TRUE : FALSE; + Curl_sendpipe_head(data, conn)); if(Curl_removeHandleFromPipeline(data, conn->recv_pipe) && recv_head) - conn->readchannel_inuse = FALSE; + Curl_pipeline_leave_read(conn); if(Curl_removeHandleFromPipeline(data, conn->send_pipe) && send_head) - conn->writechannel_inuse = FALSE; + Curl_pipeline_leave_write(conn); } static void signalPipeClose(struct curl_llist *pipeline, bool pipe_broke) @@ -2825,7 +2944,7 @@ find_oldest_idle_connection(struct SessionHandle *data) now = Curl_tvnow(); - Curl_hash_start_iterate(bc->hash, &iter); + Curl_hash_start_iterate(&bc->hash, &iter); he = Curl_hash_next_element(&iter); while(he) { @@ -2959,6 +3078,13 @@ static void prune_dead_connections(struct SessionHandle *data) } } + +static size_t max_pipeline_length(struct Curl_multi *multi) +{ + return multi ? multi->max_pipeline_length : 0; +} + + /* * Given one filled in connection struct (named needle), this function should * detect if there already is one that has all the significant details @@ -2975,17 +3101,21 @@ static bool ConnectionExists(struct SessionHandle *data, struct connectdata *needle, struct connectdata **usethis, - bool *force_reuse) + bool *force_reuse, + bool *waitpipe) { struct connectdata *check; struct connectdata *chosen = 0; bool canPipeline = IsPipeliningPossible(data, needle); +#ifdef USE_NTLM bool wantNTLMhttp = ((data->state.authhost.want & CURLAUTH_NTLM) || (data->state.authhost.want & CURLAUTH_NTLM_WB)) && (needle->handler->protocol & PROTO_FAMILY_HTTP) ? TRUE : FALSE; +#endif struct connectbundle *bundle; *force_reuse = FALSE; + *waitpipe = FALSE; /* We can't pipe if the site is blacklisted */ if(canPipeline && Curl_pipeline_site_blacklisted(data, needle)) { @@ -2994,10 +3124,11 @@ ConnectionExists(struct SessionHandle *data, /* Look up the bundle with all the connections to this particular host */ - bundle = Curl_conncache_find_bundle(data->state.conn_cache, - needle->host.name); + bundle = Curl_conncache_find_bundle(needle, data->state.conn_cache); if(bundle) { - size_t max_pipe_len = Curl_multi_max_pipeline_length(data->multi); + /* Max pipe length is zero (unlimited) for multiplexed connections */ + size_t max_pipe_len = (bundle->multiuse != BUNDLE_MULTIPLEX)? + max_pipeline_length(data->multi):0; size_t best_pipe_len = max_pipe_len; struct curl_llist_element *curr; @@ -3005,15 +3136,25 @@ ConnectionExists(struct SessionHandle *data, needle->host.name, (void *)bundle); /* We can't pipe if we don't know anything about the server */ - if(canPipeline && !bundle->server_supports_pipelining) { - infof(data, "Server doesn't support pipelining\n"); - canPipeline = FALSE; + if(canPipeline) { + if(bundle->multiuse <= BUNDLE_UNKNOWN) { + if((bundle->multiuse == BUNDLE_UNKNOWN) && data->set.pipewait) { + infof(data, "Server doesn't support multi-use yet, wait\n"); + *waitpipe = TRUE; + return FALSE; /* no re-use */ + } + + infof(data, "Server doesn't support multi-use (yet)\n"); + canPipeline = FALSE; + } } curr = bundle->conn_list->head; while(curr) { bool match = FALSE; +#if defined(USE_NTLM) bool credentialsMatch = FALSE; +#endif size_t pipeLen; /* @@ -3029,16 +3170,19 @@ ConnectionExists(struct SessionHandle *data, pipeLen = check->send_pipe->size + check->recv_pipe->size; if(canPipeline) { - /* Make sure the pipe has only GET requests */ - struct SessionHandle* sh = gethandleathead(check->send_pipe); - struct SessionHandle* rh = gethandleathead(check->recv_pipe); - if(sh) { - if(!IsPipeliningPossible(sh, check)) - continue; - } - else if(rh) { - if(!IsPipeliningPossible(rh, check)) - continue; + + if(!check->bits.multiplex) { + /* If not multiplexing, make sure the pipe has only GET requests */ + struct SessionHandle* sh = gethandleathead(check->send_pipe); + struct SessionHandle* rh = gethandleathead(check->recv_pipe); + if(sh) { + if(!IsPipeliningPossible(sh, check)) + continue; + } + else if(rh) { + if(!IsPipeliningPossible(rh, check)) + continue; + } } } else { @@ -3118,8 +3262,11 @@ ConnectionExists(struct SessionHandle *data, continue; } - if((!(needle->handler->flags & PROTOPT_CREDSPERREQUEST)) || - wantNTLMhttp) { + if((!(needle->handler->flags & PROTOPT_CREDSPERREQUEST)) +#ifdef USE_NTLM + || (wantNTLMhttp || check->ntlm.state != NTLMSTATE_NONE) +#endif + ) { /* This protocol requires credentials per connection or is HTTP+NTLM, so verify that we're using the same name and password as well */ if(!strequal(needle->user, check->user) || @@ -3127,7 +3274,9 @@ ConnectionExists(struct SessionHandle *data, /* one of them was different */ continue; } +#if defined(USE_NTLM) credentialsMatch = TRUE; +#endif } if(!needle->bits.httpproxy || needle->handler->flags&PROTOPT_SSL || @@ -3179,6 +3328,7 @@ ConnectionExists(struct SessionHandle *data, } if(match) { +#if defined(USE_NTLM) /* If we are looking for an HTTP+NTLM connection, check if this is already authenticating with the right credentials. If not, keep looking so that we can reuse NTLM connections if @@ -3197,6 +3347,7 @@ ConnectionExists(struct SessionHandle *data, chosen = check; continue; } +#endif if(canPipeline) { /* We can pipeline if we want to. Let's continue looking for @@ -3210,19 +3361,42 @@ ConnectionExists(struct SessionHandle *data, } /* We can't use the connection if the pipe is full */ - if(pipeLen >= max_pipe_len) + if(max_pipe_len && (pipeLen >= max_pipe_len)) { + infof(data, "Pipe is full, skip (%zu)\n", pipeLen); continue; - + } +#ifdef USE_NGHTTP2 + /* If multiplexed, make sure we don't go over concurrency limit */ + if(check->bits.multiplex) { + /* Multiplexed connections can only be HTTP/2 for now */ + struct http_conn *httpc = &check->proto.httpc; + if(pipeLen >= httpc->settings.max_concurrent_streams) { + infof(data, "MAX_CONCURRENT_STREAMS reached, skip (%zu)\n", + pipeLen); + continue; + } + } +#endif /* We can't use the connection if the pipe is penalized */ - if(Curl_pipeline_penalized(data, check)) + if(Curl_pipeline_penalized(data, check)) { + infof(data, "Penalized, skip\n"); continue; + } - if(pipeLen < best_pipe_len) { - /* This connection has a shorter pipe so far. We'll pick this - and continue searching */ + if(max_pipe_len) { + if(pipeLen < best_pipe_len) { + /* This connection has a shorter pipe so far. We'll pick this + and continue searching */ + chosen = check; + best_pipe_len = pipeLen; + continue; + } + } + else { + /* When not pipelining (== multiplexed), we have a match here! */ chosen = check; - best_pipe_len = pipeLen; - continue; + infof(data, "Multiplexed connection found!\n"); + break; } } else { @@ -3274,20 +3448,6 @@ ConnectionDone(struct SessionHandle *data, struct connectdata *conn) return (conn_candidate == conn) ? FALSE : TRUE; } -/* - * The given input connection struct pointer is to be stored in the connection - * cache. If the cache is already full, least interesting existing connection - * (if any) gets closed. - * - * The given connection should be unique. That must've been checked prior to - * this call. - */ -static CURLcode ConnectionStore(struct SessionHandle *data, - struct connectdata *conn) -{ - return Curl_conncache_add_conn(data->state.conn_cache, conn); -} - /* after a TCP connection to the proxy has been verified, this function does the next magic step. @@ -3533,7 +3693,7 @@ static void fix_hostname(struct SessionHandle *data, host->dispname = host->name; len = strlen(host->name); - if(host->name[len-1] == '.') + 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; @@ -3550,7 +3710,7 @@ static void fix_hostname(struct SessionHandle *data, stringprep_locale_charset ()); if(rc != IDNA_SUCCESS) infof(data, "Failed to convert %s to ACE; %s\n", - host->name, Curl_idn_strerror(conn,rc)); + host->name, Curl_idn_strerror(conn, rc)); else { /* tld_check_name() displays a warning if the host name contains "illegal" characters for this TLD */ @@ -3655,16 +3815,17 @@ static struct connectdata *allocate_conn(struct SessionHandle *data) conn->ip_version = data->set.ipver; -#if defined(USE_NTLM) && defined(NTLM_WB_ENABLED) +#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \ + defined(NTLM_WB_ENABLED) conn->ntlm_auth_hlpr_socket = CURL_SOCKET_BAD; conn->ntlm_auth_hlpr_pid = 0; conn->challenge_header = NULL; conn->response_header = NULL; #endif - if(Curl_multi_pipeline_enabled(data->multi) && - !conn->master_buffer) { - /* Allocate master_buffer to be used for pipelining */ + if(Curl_pipeline_wanted(data->multi, CURLPIPE_HTTP1) && + !conn->master_buffer) { + /* Allocate master_buffer to be used for HTTP/1 pipelining */ conn->master_buffer = calloc(BUFSIZE, sizeof (char)); if(!conn->master_buffer) goto error; @@ -3703,9 +3864,9 @@ static struct connectdata *allocate_conn(struct SessionHandle *data) conn->send_pipe = NULL; conn->recv_pipe = NULL; - Curl_safefree(conn->master_buffer); - Curl_safefree(conn->localdev); - Curl_safefree(conn); + free(conn->master_buffer); + free(conn->localdev); + free(conn); return NULL; } @@ -3772,6 +3933,13 @@ static CURLcode parseurlandfillconn(struct SessionHandle *data, *prot_missing = FALSE; + /* We might pass the entire URL into the request so we need to make sure + * there are no bad characters in there.*/ + if(strpbrk(data->change.url, "\r\n")) { + failf(data, "Illegal characters found in URL"); + return CURLE_URL_MALFORMAT; + } + /************************************************************* * Parse the URL. * @@ -3941,7 +4109,7 @@ static CURLcode parseurlandfillconn(struct SessionHandle *data, path[0] = '/'; rebuild_url = TRUE; } - else { + else if(!data->set.path_as_is) { /* sanitise paths and remove ../ and ./ sequences according to RFC3986 */ char *newp = Curl_dedotdotify(path); if(!newp) @@ -4003,7 +4171,7 @@ static CURLcode parseurlandfillconn(struct SessionHandle *data, * the host name */ result = parse_url_login(data, conn, userp, passwdp, optionsp); - if(result != CURLE_OK) + if(result) return result; if(conn->host.name[0] == '[') { @@ -4024,7 +4192,7 @@ static CURLcode parseurlandfillconn(struct SessionHandle *data, /* The address scope was well formed. Knock it out of the hostname. */ memmove(percent, endp, strlen(endp)+1); - conn->scope = (unsigned int)scope; + conn->scope_id = (unsigned int)scope; } else { /* Zone identifier is not numeric */ @@ -4046,11 +4214,11 @@ static CURLcode parseurlandfillconn(struct SessionHandle *data, } } if(scopeidx > 0) { + char *p = percent + identifier_offset + strlen(ifname); + /* Remove zone identifier from hostname */ - memmove(percent, - percent + identifier_offset + strlen(ifname), - identifier_offset + strlen(ifname)); - conn->scope = scopeidx; + memmove(percent, p, strlen(p) + 1); + conn->scope_id = scopeidx; } else #endif /* HAVE_NET_IF_H && IFNAMSIZ */ @@ -4059,9 +4227,9 @@ static CURLcode parseurlandfillconn(struct SessionHandle *data, } } - if(data->set.scope) + if(data->set.scope_id) /* Override any scope that was set above. */ - conn->scope = data->set.scope; + conn->scope_id = data->set.scope_id; /* Remove the fragment part of the path. Per RFC 2396, this is always the last part of the URI. We are looking for the first '#' so that we deal @@ -4153,7 +4321,7 @@ static CURLcode setup_connection_internals(struct connectdata *conn) if(p->setup_connection) { result = (*p->setup_connection)(conn); - if(result != CURLE_OK) + if(result) return result; p = conn->handler; /* May have changed. */ @@ -4327,9 +4495,8 @@ static char *detect_proxy(struct connectdata *conn) prox=curl_getenv(proxy_env); } - if(prox && *prox) { /* don't count "" strings */ + if(prox) proxy = prox; /* use this */ - } else { proxy = curl_getenv("all_proxy"); /* default proxy to use */ if(!proxy) @@ -4337,8 +4504,7 @@ static char *detect_proxy(struct connectdata *conn) } } /* if(!check_noproxy(conn->host.name, no_proxy)) - it wasn't specified non-proxy */ - if(no_proxy) - free(no_proxy); + free(no_proxy); #else /* !CURL_DISABLE_HTTP */ @@ -4352,7 +4518,6 @@ static char *detect_proxy(struct connectdata *conn) * If this is supposed to use a proxy, we need to figure out the proxy * host name, so that we can re-use an existing connection * that may exist registered to the same proxy host. - * proxy will be freed before this function returns. */ static CURLcode parse_proxy(struct SessionHandle *data, struct connectdata *conn, char *proxy) @@ -4389,13 +4554,12 @@ static CURLcode parse_proxy(struct SessionHandle *data, /* Is there a username and password given in this proxy url? */ atsign = strchr(proxyptr, '@'); if(atsign) { - CURLcode res = CURLE_OK; char *proxyuser = NULL; char *proxypasswd = NULL; - - res = parse_login_details(proxyptr, atsign - proxyptr, - &proxyuser, &proxypasswd, NULL); - if(!res) { + CURLcode result = + parse_login_details(proxyptr, atsign - proxyptr, + &proxyuser, &proxypasswd, NULL); + if(!result) { /* found user and password, rip them out. note that we are unescaping them, as there is otherwise no way to have a username or password with reserved characters like ':' in @@ -4407,7 +4571,7 @@ static CURLcode parse_proxy(struct SessionHandle *data, conn->proxyuser = strdup(""); if(!conn->proxyuser) - res = CURLE_OUT_OF_MEMORY; + result = CURLE_OUT_OF_MEMORY; else { Curl_safefree(conn->proxypasswd); if(proxypasswd && strlen(proxypasswd) < MAX_CURL_PASSWORD_LENGTH) @@ -4416,25 +4580,22 @@ static CURLcode parse_proxy(struct SessionHandle *data, conn->proxypasswd = strdup(""); if(!conn->proxypasswd) - res = CURLE_OUT_OF_MEMORY; + result = CURLE_OUT_OF_MEMORY; } - if(!res) { + if(!result) { conn->bits.proxy_user_passwd = TRUE; /* enable it */ atsign++; /* the right side of the @-letter */ - if(atsign) - proxyptr = atsign; /* now use this instead */ - else - res = CURLE_OUT_OF_MEMORY; + proxyptr = atsign; /* now use this instead */ } } - Curl_safefree(proxyuser); - Curl_safefree(proxypasswd); + free(proxyuser); + free(proxypasswd); - if(res) - return res; + if(result) + return result; } /* start scanning for port number at this point */ @@ -4595,7 +4756,7 @@ static CURLcode parse_url_login(struct SessionHandle *data, /* We could use the login information in the URL so extract it */ result = parse_login_details(login, ptr - login - 1, &userp, &passwdp, &optionsp); - if(result != CURLE_OK) + if(result) goto out; if(userp) { @@ -4643,9 +4804,9 @@ static CURLcode parse_url_login(struct SessionHandle *data, out: - Curl_safefree(userp); - Curl_safefree(passwdp); - Curl_safefree(optionsp); + free(userp); + free(passwdp); + free(optionsp); return result; } @@ -4733,7 +4894,7 @@ static CURLcode parse_login_details(const char *login, const size_t len, if(!result && passwdp && plen) { pbuf = malloc(plen + 1); if(!pbuf) { - Curl_safefree(ubuf); + free(ubuf); result = CURLE_OUT_OF_MEMORY; } } @@ -4742,8 +4903,8 @@ static CURLcode parse_login_details(const char *login, const size_t len, if(!result && optionsp && olen) { obuf = malloc(olen + 1); if(!obuf) { - Curl_safefree(pbuf); - Curl_safefree(ubuf); + free(pbuf); + free(ubuf); result = CURLE_OUT_OF_MEMORY; } } @@ -5022,6 +5183,32 @@ static CURLcode resolve_server(struct SessionHandle *data, /* set a pointer to the hostname we display */ fix_hostname(data, conn, &conn->host); +#ifdef USE_UNIX_SOCKETS + if(data->set.str[STRING_UNIX_SOCKET_PATH]) { + /* Unix domain sockets are local. The host gets ignored, just use the + * specified domain socket address. Do not cache "DNS entries". There is + * no DNS involved and we already have the filesystem path available */ + const char *path = data->set.str[STRING_UNIX_SOCKET_PATH]; + + hostaddr = calloc(1, sizeof(struct Curl_dns_entry)); + if(!hostaddr) + result = CURLE_OUT_OF_MEMORY; + else if((hostaddr->addr = Curl_unix2addr(path)) != NULL) + hostaddr->inuse++; + else { + /* Long paths are not supported for now */ + if(strlen(path) >= sizeof(((struct sockaddr_un *)0)->sun_path)) { + failf(data, "Unix socket path too long: '%s'", path); + result = CURLE_COULDNT_RESOLVE_HOST; + } + else + result = CURLE_OUT_OF_MEMORY; + free(hostaddr); + hostaddr = NULL; + } + } + else +#endif if(!conn->proxy.name || !*conn->proxy.name) { /* If not connecting via a proxy, extract the port from the URL, if it is * there, thus overriding any defaults that might have been set above. */ @@ -5079,8 +5266,7 @@ static CURLcode resolve_server(struct SessionHandle *data, static void reuse_conn(struct connectdata *old_conn, struct connectdata *conn) { - if(old_conn->proxy.rawalloc) - free(old_conn->proxy.rawalloc); + free(old_conn->proxy.rawalloc); /* free the SSL config struct from this connection struct as this was allocated in vain and is targeted for destruction */ @@ -5168,8 +5354,9 @@ static CURLcode create_conn(struct SessionHandle *data, bool reuse; char *proxy = NULL; bool prot_missing = FALSE; - bool no_connections_available = FALSE; + bool connections_available = TRUE; bool force_reuse = FALSE; + bool waitpipe = FALSE; size_t max_host_connections = Curl_multi_max_host_connections(data->multi); size_t max_total_connections = Curl_multi_max_total_connections(data->multi); @@ -5250,7 +5437,7 @@ static CURLcode create_conn(struct SessionHandle *data, result = parseurlandfillconn(data, conn, &prot_missing, &user, &passwd, &options); - if(result != CURLE_OK) + if(result) goto out; /************************************************************* @@ -5310,7 +5497,7 @@ static CURLcode create_conn(struct SessionHandle *data, *************************************************************/ if(conn->bits.proxy_user_passwd) { result = parse_proxy_auth(data, conn); - if(result != CURLE_OK) + if(result) goto out; } @@ -5329,14 +5516,19 @@ static CURLcode create_conn(struct SessionHandle *data, if(data->set.str[STRING_NOPROXY] && check_noproxy(conn->host.name, data->set.str[STRING_NOPROXY])) { - if(proxy) { - free(proxy); /* proxy is in exception list */ - proxy = NULL; - } + free(proxy); /* proxy is in exception list */ + proxy = NULL; } else if(!proxy) proxy = detect_proxy(conn); +#ifdef USE_UNIX_SOCKETS + if(proxy && data->set.str[STRING_UNIX_SOCKET_PATH]) { + free(proxy); /* Unix domain sockets cannot be proxied, so disable it */ + proxy = NULL; + } +#endif + if(proxy && (!*proxy || (conn->handler->flags & PROTOPT_NONETWORK))) { free(proxy); /* Don't bother with an empty proxy string or if the protocol doesn't work with network */ @@ -5351,7 +5543,8 @@ static CURLcode create_conn(struct SessionHandle *data, if(proxy) { result = parse_proxy(data, conn, proxy); - Curl_safefree(proxy); /* parse_proxy copies the proxy string */ + free(proxy); /* parse_proxy copies the proxy string */ + proxy = NULL; if(result) goto out; @@ -5372,8 +5565,10 @@ static CURLcode create_conn(struct SessionHandle *data, conn->bits.httpproxy = TRUE; #endif } - else + else { conn->bits.httpproxy = FALSE; /* not a HTTP proxy */ + conn->bits.tunnel_proxy = FALSE; /* no tunneling if not HTTP */ + } conn->bits.proxy = TRUE; } else { @@ -5397,16 +5592,16 @@ static CURLcode create_conn(struct SessionHandle *data, * Figure out the remote port number and fix it in the URL *************************************************************/ result = parse_remote_port(data, conn); - if(result != CURLE_OK) + if(result) goto out; /* Check for overridden login details and set them accordingly so they they are known when protocol->setup_connection is called! */ result = override_login(data, conn, &user, &passwd, &options); - if(result != CURLE_OK) + if(result) goto out; result = set_login(conn, user, passwd, options); - if(result != CURLE_OK) + if(result) goto out; /************************************************************* @@ -5414,7 +5609,7 @@ static CURLcode create_conn(struct SessionHandle *data, * we figured out what/if proxy to use. *************************************************************/ result = setup_connection_internals(conn); - if(result != CURLE_OK) + if(result) goto out; conn->recv[FIRSTSOCKET] = Curl_recv_plain; @@ -5434,11 +5629,11 @@ static CURLcode create_conn(struct SessionHandle *data, result = conn->handler->connect_it(conn, &done); /* Setup a "faked" transfer that'll do nothing */ - if(CURLE_OK == result) { + if(!result) { conn->data = data; conn->bits.tcpconnect[FIRSTSOCKET] = TRUE; /* we are "connected */ - ConnectionStore(data, conn); + Curl_conncache_add_conn(data->state.conn_cache, conn); /* * Setup whatever necessary for a resumed transfer @@ -5456,7 +5651,7 @@ static CURLcode create_conn(struct SessionHandle *data, } /* since we skip do_init() */ - do_init(conn); + Curl_init_do(data, conn); goto out; } @@ -5503,7 +5698,7 @@ static CURLcode create_conn(struct SessionHandle *data, if(data->set.reuse_fresh && !data->state.this_is_a_follow) reuse = FALSE; else - reuse = ConnectionExists(data, conn, &conn_temp, &force_reuse); + reuse = ConnectionExists(data, conn, &conn_temp, &force_reuse, &waitpipe); /* If we found a reusable connection, we may still want to open a new connection if we are pipelining. */ @@ -5540,18 +5735,24 @@ static CURLcode create_conn(struct SessionHandle *data, /* set a pointer to the hostname we display */ fix_hostname(data, conn, &conn->host); - infof(data, "Re-using existing connection! (#%ld) with host %s\n", + infof(data, "Re-using existing connection! (#%ld) with %s %s\n", conn->connection_id, + conn->bits.proxy?"proxy":"host", conn->proxy.name?conn->proxy.dispname:conn->host.dispname); } else { /* We have decided that we want a new connection. However, we may not be able to do that if we have reached the limit of how many connections we are allowed to open. */ - struct connectbundle *bundle; + struct connectbundle *bundle = NULL; + + if(waitpipe) + /* There is a connection that *might* become usable for pipelining + "soon", and we wait for that */ + connections_available = FALSE; + else + bundle = Curl_conncache_find_bundle(conn, data->state.conn_cache); - bundle = Curl_conncache_find_bundle(data->state.conn_cache, - conn->host.name); if(max_host_connections > 0 && bundle && (bundle->num_connections >= max_host_connections)) { struct connectdata *conn_candidate; @@ -5564,11 +5765,15 @@ static CURLcode create_conn(struct SessionHandle *data, conn_candidate->data = data; (void)Curl_disconnect(conn_candidate, /* dead_connection */ FALSE); } - else - no_connections_available = TRUE; + else { + infof(data, "No more connections allowed to host: %d\n", + max_host_connections); + connections_available = FALSE; + } } - if(max_total_connections > 0 && + if(connections_available && + (max_total_connections > 0) && (data->state.conn_cache->num_connections >= max_total_connections)) { struct connectdata *conn_candidate; @@ -5580,12 +5785,13 @@ static CURLcode create_conn(struct SessionHandle *data, conn_candidate->data = data; (void)Curl_disconnect(conn_candidate, /* dead_connection */ FALSE); } - else - no_connections_available = TRUE; + else { + infof(data, "No connections available in cache\n"); + connections_available = FALSE; + } } - - if(no_connections_available) { + if(!connections_available) { infof(data, "No connections available.\n"); conn_free(conn); @@ -5599,9 +5805,10 @@ static CURLcode create_conn(struct SessionHandle *data, * This is a brand new connection, so let's store it in the connection * cache of ours! */ - ConnectionStore(data, conn); + Curl_conncache_add_conn(data->state.conn_cache, conn); } +#if defined(USE_NTLM) /* If NTLM is requested in a part of this connection, make sure we don't assume the state is fine as this is a fresh connection and NTLM is connection based. */ @@ -5610,19 +5817,20 @@ static CURLcode create_conn(struct SessionHandle *data, infof(data, "NTLM picked AND auth done set, clear picked!\n"); data->state.authhost.picked = CURLAUTH_NONE; } + if((data->state.authproxy.picked & (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) && data->state.authproxy.done) { infof(data, "NTLM-proxy picked AND auth done set, clear picked!\n"); data->state.authproxy.picked = CURLAUTH_NONE; } - +#endif } /* Mark the connection as used */ conn->inuse = TRUE; /* Setup and init stuff before DO starts, in preparing for the transfer. */ - do_init(conn); + Curl_init_do(data, conn); /* * Setup whatever necessary for a resumed transfer @@ -5637,8 +5845,6 @@ static CURLcode create_conn(struct SessionHandle *data, * Inherit the proper values from the urldata struct AFTER we have arranged * the persistent connection stuff */ - conn->fread_func = data->set.fread_func; - conn->fread_in = data->set.in; conn->seek_func = data->set.seek_func; conn->seek_client = data->set.seek_client; @@ -5649,10 +5855,10 @@ static CURLcode create_conn(struct SessionHandle *data, out: - Curl_safefree(options); - Curl_safefree(passwd); - Curl_safefree(user); - Curl_safefree(proxy); + free(options); + free(passwd); + free(user); + free(proxy); return result; } @@ -5747,14 +5953,14 @@ CURLcode Curl_connect(struct SessionHandle *data, bool *asyncp, bool *protocol_done) { - CURLcode code; + CURLcode result; *asyncp = FALSE; /* assume synchronous resolves by default */ /* call the stuff that needs to be called */ - code = create_conn(data, in_connect, asyncp); + result = create_conn(data, in_connect, asyncp); - if(CURLE_OK == code) { + if(!result) { /* no error */ if((*in_connect)->send_pipe->size || (*in_connect)->recv_pipe->size) /* pipelining */ @@ -5763,23 +5969,23 @@ CURLcode Curl_connect(struct SessionHandle *data, /* DNS resolution is done: that's either because this is a reused connection, in which case DNS was unnecessary, or because DNS really did finish already (synch resolver/fast async resolve) */ - code = Curl_setup_conn(*in_connect, protocol_done); + result = Curl_setup_conn(*in_connect, protocol_done); } } - if(code == CURLE_NO_CONNECTION_AVAILABLE) { + if(result == CURLE_NO_CONNECTION_AVAILABLE) { *in_connect = NULL; - return code; + return result; } - if(code && *in_connect) { + if(result && *in_connect) { /* We're not allowed to return failure with memory left allocated in the connectdata struct, free those here */ Curl_disconnect(*in_connect, FALSE); /* close the connection */ *in_connect = NULL; /* return a NULL */ } - return code; + return result; } CURLcode Curl_done(struct connectdata **connp, @@ -5796,37 +6002,19 @@ CURLcode Curl_done(struct connectdata **connp, conn = *connp; data = conn->data; - if(conn->bits.done) + DEBUGF(infof(data, "Curl_done\n")); + + if(data->state.done) /* Stop if Curl_done() has already been called */ return CURLE_OK; Curl_getoff_all_pipelines(data, conn); - if((conn->send_pipe->size + conn->recv_pipe->size != 0 && - !data->set.reuse_forbid && - !conn->bits.close)) - /* Stop if pipeline is not empty and we do not have to close - connection. */ - return CURLE_OK; - - conn->bits.done = TRUE; /* called just now! */ - /* Cleanup possible redirect junk */ - if(data->req.newurl) { - free(data->req.newurl); - data->req.newurl = NULL; - } - if(data->req.location) { - free(data->req.location); - data->req.location = NULL; - } - - Curl_resolver_cancel(conn); - - if(conn->dns_entry) { - Curl_resolv_unlock(data, conn->dns_entry); /* done with this */ - conn->dns_entry = NULL; - } + free(data->req.newurl); + data->req.newurl = NULL; + free(data->req.location); + data->req.location = NULL; switch(status) { case CURLE_ABORTED_BY_CALLBACK: @@ -5850,12 +6038,27 @@ CURLcode Curl_done(struct connectdata **connp, if(!result && Curl_pgrsDone(conn)) result = CURLE_ABORTED_BY_CALLBACK; + if((conn->send_pipe->size + conn->recv_pipe->size != 0 && + !data->set.reuse_forbid && + !conn->bits.close)) { + /* Stop if pipeline is not empty and we do not have to close + connection. */ + DEBUGF(infof(data, "Connection still in use, no more Curl_done now!\n")); + return CURLE_OK; + } + + data->state.done = TRUE; /* called just now! */ + Curl_resolver_cancel(conn); + + if(conn->dns_entry) { + Curl_resolv_unlock(data, conn->dns_entry); /* done with this */ + conn->dns_entry = NULL; + } + /* if the transfer was completed in a paused state there can be buffered data left to write and then kill */ - if(data->state.tempwrite) { - free(data->state.tempwrite); - data->state.tempwrite = NULL; - } + free(data->state.tempwrite); + data->state.tempwrite = NULL; /* if data->set.reuse_forbid is TRUE, it means the libcurl client has forced us to close this connection. This is ignored for requests taking @@ -5872,9 +6075,12 @@ CURLcode Curl_done(struct connectdata **connp, but currently we have no such detail knowledge. */ - if((data->set.reuse_forbid && !(conn->ntlm.state == NTLMSTATE_TYPE2 || - conn->proxyntlm.state == NTLMSTATE_TYPE2)) - || conn->bits.close || premature) { + if((data->set.reuse_forbid +#if defined(USE_NTLM) + && !(conn->ntlm.state == NTLMSTATE_TYPE2 || + conn->proxyntlm.state == NTLMSTATE_TYPE2) +#endif + ) || conn->bits.close || premature) { CURLcode res2 = Curl_disconnect(conn, premature); /* close connection */ /* If we had an error already, make sure we return that one. But @@ -5906,20 +6112,24 @@ CURLcode Curl_done(struct connectdata **connp, } /* - * do_init() inits the readwrite session. This is inited each time (in the DO - * function before the protocol-specific DO functions are invoked) for a - * transfer, sometimes multiple times on the same SessionHandle. Make sure + * Curl_init_do() inits the readwrite session. This is inited each time (in + * the DO function before the protocol-specific DO functions are invoked) for + * a transfer, sometimes multiple times on the same SessionHandle. Make sure * nothing in here depends on stuff that are setup dynamically for the * transfer. + * + * Allow this function to get called with 'conn' set to NULL. */ -static CURLcode do_init(struct connectdata *conn) +CURLcode Curl_init_do(struct SessionHandle *data, struct connectdata *conn) { - struct SessionHandle *data = conn->data; struct SingleRequest *k = &data->req; - conn->bits.done = FALSE; /* Curl_done() is not called yet */ - conn->bits.do_more = FALSE; /* by default there's no curl_do_more() to use */ + if(conn) + conn->bits.do_more = FALSE; /* by default there's no curl_do_more() to + * use */ + + data->state.done = FALSE; /* Curl_done() is not called yet */ data->state.expect100header = FALSE; if(data->set.opt_no_body) @@ -5986,7 +6196,7 @@ CURLcode Curl_do(struct connectdata **connp, bool *done) if(!data->multi) { result = Curl_reconnect_request(connp); - if(result == CURLE_OK) { + if(!result) { /* ... finally back to actually retry the DO phase */ conn = *connp; /* re-assign conn since Curl_reconnect_request creates a new connection */ @@ -5997,7 +6207,7 @@ CURLcode Curl_do(struct connectdata **connp, bool *done) return result; } - if((result == CURLE_OK) && *done) + if(!result && *done) /* do_complete must be called after the protocol-specific DO function */ do_complete(conn); } diff --git a/Utilities/cmcurl/lib/url.h b/Utilities/cmcurl/lib/url.h index cd46a92..f9667cb 100644 --- a/Utilities/cmcurl/lib/url.h +++ b/Utilities/cmcurl/lib/url.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -27,6 +27,7 @@ * Prototypes for library-wide functions provided by url.c */ +CURLcode Curl_init_do(struct SessionHandle *data, struct connectdata *conn); CURLcode Curl_open(struct SessionHandle **curl); CURLcode Curl_init_userdefined(struct UserDefined *set); CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, @@ -69,6 +70,9 @@ void Curl_close_connections(struct SessionHandle *data); #define CURL_DEFAULT_PROXY_PORT 1080 /* default proxy port unless specified */ #define CURL_DEFAULT_SOCKS5_GSSAPI_SERVICE "rcmd" /* default socks5 gssapi service */ +#define CURL_DEFAULT_PROXY_SERVICE_NAME "HTTP" /* default negotiate proxy + service */ +#define CURL_DEFAULT_SERVICE_NAME "HTTP" /* default negotiate service */ CURLcode Curl_connected_proxy(struct connectdata *conn, int sockindex); diff --git a/Utilities/cmcurl/lib/urldata.h b/Utilities/cmcurl/lib/urldata.h index 8594c2f..b1c2056 100644 --- a/Utilities/cmcurl/lib/urldata.h +++ b/Utilities/cmcurl/lib/urldata.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -40,6 +40,8 @@ #define PORT_IMAPS 993 #define PORT_POP3 110 #define PORT_POP3S 995 +#define PORT_SMB 445 +#define PORT_SMBS 445 #define PORT_SMTP 25 #define PORT_SMTPS 465 /* sometimes called SSMTP */ #define PORT_RTSP 554 @@ -64,6 +66,7 @@ #define PROTO_FAMILY_HTTP (CURLPROTO_HTTP|CURLPROTO_HTTPS) #define PROTO_FAMILY_FTP (CURLPROTO_FTP|CURLPROTO_FTPS) #define PROTO_FAMILY_POP3 (CURLPROTO_POP3|CURLPROTO_POP3S) +#define PROTO_FAMILY_SMB (CURLPROTO_SMB|CURLPROTO_SMBS) #define PROTO_FAMILY_SMTP (CURLPROTO_SMTP|CURLPROTO_SMTPS) #define DEFAULT_CONNCACHE_SIZE 5 @@ -79,38 +82,12 @@ #include "cookie.h" #include "formdata.h" -#ifdef USE_SSLEAY #ifdef USE_OPENSSL -#include <openssl/rsa.h> -#include <openssl/crypto.h> -#include <openssl/x509.h> -#include <openssl/pem.h> #include <openssl/ssl.h> -#include <openssl/err.h> #ifdef HAVE_OPENSSL_ENGINE_H #include <openssl/engine.h> #endif -#ifdef HAVE_OPENSSL_PKCS12_H -#include <openssl/pkcs12.h> -#endif -#else /* SSLeay-style includes */ -#include <rsa.h> -#include <crypto.h> -#include <x509.h> -#include <pem.h> -#include <ssl.h> -#include <err.h> -#ifdef HAVE_OPENSSL_ENGINE_H -#include <engine.h> -#endif -#ifdef HAVE_OPENSSL_PKCS12_H -#include <pkcs12.h> -#endif #endif /* USE_OPENSSL */ -#ifdef USE_GNUTLS -#error Configuration error; cannot use GnuTLS *and* OpenSSL. -#endif -#endif /* USE_SSLEAY */ #ifdef USE_GNUTLS #include <gnutls/gnutls.h> @@ -138,15 +115,12 @@ #include <pk11pub.h> #endif -#ifdef USE_QSOSSL -#include <qsossl.h> -#endif - #ifdef USE_GSKIT #include <gskssl.h> #endif #ifdef USE_AXTLS +#include <axTLS/config.h> #include <axTLS/ssl.h> #undef malloc #undef calloc @@ -195,6 +169,7 @@ #include "ssh.h" #include "http.h" #include "rtsp.h" +#include "smb.h" #include "wildcard.h" #include "multihandle.h" @@ -223,6 +198,8 @@ #define HEADERSIZE 256 #define CURLEASY_MAGIC_NUMBER 0xc0dedbadU +#define GOOD_EASY_HANDLE(x) \ + ((x) && (((struct SessionHandle *)(x))->magic == CURLEASY_MAGIC_NUMBER)) /* Some convenience macros to get the larger/smaller value out of two given. We prefix with CURL to prevent name collisions. */ @@ -288,13 +265,13 @@ struct ssl_connect_data { current state of the connection. */ bool use; ssl_connection_state state; -#ifdef USE_SSLEAY +#ifdef USE_OPENSSL /* these ones requires specific SSL-types */ SSL_CTX* ctx; SSL* handle; X509* server_cert; ssl_connect_state connecting_state; -#endif /* USE_SSLEAY */ +#endif /* USE_OPENSSL */ #ifdef USE_GNUTLS gnutls_session_t session; gnutls_certificate_credentials_t cred; @@ -328,9 +305,6 @@ struct ssl_connect_data { PK11GenericObject *obj_clicert; ssl_connect_state connecting_state; #endif /* USE_NSS */ -#ifdef USE_QSOSSL - SSLHandle *handle; -#endif /* USE_QSOSSL */ #ifdef USE_GSKIT gsk_handle handle; int iocport; @@ -350,6 +324,9 @@ struct ssl_connect_data { size_t encdata_offset, decdata_offset; unsigned char *encdata_buffer, *decdata_buffer; 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 */ #endif /* USE_SCHANNEL */ #ifdef USE_DARWINSSL SSLContextRef ssl_ctx; @@ -366,6 +343,7 @@ struct ssl_config_data { 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 */ char *CApath; /* certificate dir (doesn't work on windows) */ char *CAfile; /* certificate to verify peer against */ const char *CRLfile; /* CRL to check certificate revocation */ @@ -378,6 +356,7 @@ struct ssl_config_data { void *fsslctxp; /* parameter for call back */ bool sessionid; /* cache session IDs or not */ bool certinfo; /* gather lots of certificate info */ + bool falsestart; #ifdef USE_TLS_SRP char *username; /* TLS username (for, e.g., SRP) */ @@ -398,6 +377,10 @@ struct curl_ssl_session { /* Struct used for Digest challenge-response authentication */ struct digestdata { +#if defined(USE_WINDOWS_SSPI) + BYTE *input_token; + size_t input_token_len; +#else char *nonce; char *cnonce; char *realm; @@ -407,6 +390,7 @@ struct digestdata { char *qop; char *algorithm; int nc; /* nounce count */ +#endif }; typedef enum { @@ -426,8 +410,9 @@ typedef enum { #endif /* Struct used for GSSAPI (Kerberos V5) authentication */ -#if defined(USE_WINDOWS_SSPI) +#if defined(USE_KERBEROS5) struct kerberos5data { +#if defined(USE_WINDOWS_SSPI) CredHandle *credentials; CtxtHandle *context; TCHAR *spn; @@ -435,22 +420,26 @@ struct kerberos5data { SEC_WINNT_AUTH_IDENTITY *p_identity; size_t token_max; BYTE *output_token; +#else + gss_ctx_id_t context; + gss_name_t spn; +#endif }; #endif /* Struct used for NTLM challenge-response authentication */ +#if defined(USE_NTLM) struct ntlmdata { curlntlm state; #ifdef USE_WINDOWS_SSPI - CredHandle handle; - CtxtHandle c_handle; + CredHandle *credentials; + CtxtHandle *context; SEC_WINNT_AUTH_IDENTITY identity; SEC_WINNT_AUTH_IDENTITY *p_identity; - size_t max_token_length; + size_t token_max; BYTE *output_token; - int has_handles; - void *type_2; - unsigned long n_type_2; + BYTE *input_token; + size_t input_token_len; #else unsigned int flags; unsigned char nonce[8]; @@ -458,6 +447,7 @@ struct ntlmdata { unsigned int target_info_len; #endif }; +#endif #ifdef USE_SPNEGO struct negotiatedata { @@ -472,12 +462,12 @@ struct negotiatedata { #else #ifdef USE_WINDOWS_SSPI DWORD status; - CtxtHandle *context; CredHandle *credentials; + CtxtHandle *context; SEC_WINNT_AUTH_IDENTITY identity; SEC_WINNT_AUTH_IDENTITY *p_identity; TCHAR *server_name; - size_t max_token_length; + size_t token_max; BYTE *output_token; size_t output_token_length; #endif @@ -531,11 +521,6 @@ struct ConnectBits { requests */ bool netrc; /* name+password provided by netrc */ bool userpwd_in_url; /* name+password found in url */ - - bool done; /* set to FALSE when Curl_do() is called and set to TRUE - when Curl_done() is called, to prevent Curl_done() to - get invoked twice when the multi interface is - used. */ bool stream_was_rewound; /* Indicates that the stream was rewound after a request read past the end of its response byte boundary */ @@ -545,6 +530,7 @@ struct ConnectBits { bool bound; /* set true if bind() has already been done on this socket/ connection */ bool type_set; /* type= was used in the URL */ + bool multiplex; /* connection is multiplexed */ }; struct hostname { @@ -617,12 +603,6 @@ enum upgrade101 { UPGR101_WORKING /* talking upgraded protocol */ }; -enum negotiatenpn { - NPN_INIT, /* default state */ - NPN_HTTP1_1, /* HTTP/1.1 negotiated */ - NPN_HTTP2 /* HTTP2 (draft-xx) negotiated */ -}; - /* * Request specific data in the easy handle (SessionHandle). Previously, * these members were on the connectdata struct but since a conn struct may @@ -680,7 +660,6 @@ struct SingleRequest { #define IDENTITY 0 /* No encoding */ #define DEFLATE 1 /* zlib deflate [RFC 1950 & 1951] */ #define GZIP 2 /* gzip algorithm [RFC 1952] */ -#define COMPRESS 3 /* Not handled, added for completeness */ #ifdef HAVE_LIBZ zlibInitState zlib_init; /* possible zlib init state; @@ -883,7 +862,7 @@ struct connectdata { the ip_addr itself. */ char ip_addr_str[MAX_IPADR_LEN]; - unsigned int scope; /* address scope for IPv6 */ + unsigned int scope_id; /* Scope id for IPv6 */ int socktype; /* SOCK_STREAM or SOCK_DGRAM */ @@ -974,8 +953,8 @@ struct connectdata { char *te; /* TE: request header */ } allocptr; - int sec_complete; /* if kerberos is enabled for this connection */ #ifdef HAVE_GSSAPI + int sec_complete; /* if Kerberos is enabled for this connection */ enum protection_level command_prot; enum protection_level data_prot; enum protection_level request_data_prot; @@ -986,7 +965,7 @@ struct connectdata { struct sockaddr_in local_addr; #endif -#if defined(USE_WINDOWS_SSPI) /* Consider moving some of the above GSS-API */ +#if defined(USE_KERBEROS5) /* Consider moving some of the above GSS-API */ struct kerberos5data krb5; /* variables into the structure definition, */ #endif /* however, some of them are ftp specific. */ @@ -1013,22 +992,20 @@ struct connectdata { /*************** Request - specific items ************/ - /* previously this was in the urldata struct */ - curl_read_callback fread_func; /* function that reads the input */ - void *fread_in; /* pointer to pass to the fread() above */ - +#if defined(USE_NTLM) struct ntlmdata ntlm; /* NTLM differs from other authentication schemes because it authenticates connections, not single requests! */ struct ntlmdata proxyntlm; /* NTLM data for proxy */ -#if defined(USE_NTLM) && defined(NTLM_WB_ENABLED) +#if defined(NTLM_WB_ENABLED) /* used for communication with Samba's winbind daemon helper ntlm_auth */ curl_socket_t ntlm_auth_hlpr_socket; pid_t ntlm_auth_hlpr_pid; char* challenge_header; char* response_header; #endif +#endif char syserr_buf [256]; /* buffer for Curl_strerror() */ @@ -1051,6 +1028,7 @@ struct connectdata { struct pop3_conn pop3c; struct smtp_conn smtpc; struct rtsp_conn rtspc; + struct smb_conn smbc; void *generic; /* RTMP and LDAP use this */ } proto; @@ -1081,7 +1059,7 @@ struct connectdata { } tunnel_state[2]; /* two separate ones to allow FTP */ struct connectbundle *bundle; /* The bundle we are member of */ - enum negotiatenpn negnpn; + int negnpn; /* APLN or NPN TLS negotiated protocol, CURL_HTTP_VERSION* */ }; /* The end of connectdata. */ @@ -1279,9 +1257,9 @@ struct UrlState { void *resolver; /* resolver state, if it is used in the URL state - ares_channel f.e. */ -#if defined(USE_SSLEAY) && defined(HAVE_OPENSSL_ENGINE_H) +#if defined(USE_OPENSSL) && defined(HAVE_OPENSSL_ENGINE_H) ENGINE *engine; -#endif /* USE_SSLEAY */ +#endif /* USE_OPENSSL */ struct timeval expiretime; /* set this with Curl_expire() only */ struct Curl_tree timenode; /* for the splay stuff */ struct curl_llist *timeoutlist; /* list of pending timeouts */ @@ -1325,10 +1303,15 @@ struct UrlState { long rtsp_next_server_CSeq; /* the session's next server CSeq */ long rtsp_CSeq_recv; /* most recent CSeq received */ - /* if true, force SSL connection retry (workaround for certain servers) */ - bool ssl_connect_retry; curl_off_t infilesize; /* size of file to upload, -1 means unknown. Copied from set.filesize at start of operation */ + + int drain; /* Increased when this stream has data to read, even if its + socket not necessarily is readable. Decreased when + checked. */ + bool done; /* set to FALSE when Curl_do() is called and set to TRUE when + Curl_done() is called, to prevent Curl_done() to get invoked + twice when the multi interface is used. */ }; @@ -1378,13 +1361,13 @@ enum dupstring { STRING_KRB_LEVEL, /* krb security level */ STRING_NETRC_FILE, /* if not NULL, use this instead of trying to find $HOME/.netrc */ - STRING_COPYPOSTFIELDS, /* if POST, set the fields' values here */ STRING_PROXY, /* proxy to use */ STRING_SET_RANGE, /* range, if used */ STRING_SET_REFERER, /* custom string for the HTTP referer field */ STRING_SET_URL, /* what original URL to work on */ STRING_SSL_CAPATH, /* CA directory name (doesn't work on windows) */ STRING_SSL_CAFILE, /* certificate file to verify peer against */ + STRING_SSL_PINNEDPUBLICKEY, /* public key file to verify peer against */ STRING_SSL_CIPHER_LIST, /* list of ciphers to use */ STRING_SSL_EGDSOCKET, /* path to file containing the EGD daemon socket */ STRING_SSL_RANDOM_FILE, /* path to file containing "random" data */ @@ -1408,19 +1391,31 @@ enum dupstring { STRING_SSH_KNOWNHOSTS, /* file name of knownhosts file */ #endif #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) - STRING_SOCKS5_GSSAPI_SERVICE, /* GSSAPI service name */ + STRING_SOCKS5_GSSAPI_SERVICE, /* GSSAPI service name */ + STRING_PROXY_SERVICE_NAME, /* Proxy service name */ + STRING_SERVICE_NAME, /* Service name */ #endif STRING_MAIL_FROM, STRING_MAIL_AUTH, #ifdef USE_TLS_SRP - STRING_TLSAUTH_USERNAME, /* TLS auth <username> */ - STRING_TLSAUTH_PASSWORD, /* TLS auth <password> */ + STRING_TLSAUTH_USERNAME, /* TLS auth <username> */ + STRING_TLSAUTH_PASSWORD, /* TLS auth <password> */ #endif + STRING_BEARER, /* <bearer>, if used */ +#ifdef USE_UNIX_SOCKETS + STRING_UNIX_SOCKET_PATH, /* path to Unix socket, if used */ +#endif + + /* -- end of zero-terminated strings -- */ - STRING_BEARER, /* <bearer>, if used */ + STRING_LASTZEROTERMINATED, + + /* -- below this are pointers to binary data that cannot be strdup'ed. + Each such pointer must be added manually to Curl_dupset() --- */ + + STRING_COPYPOSTFIELDS, /* if POST, set the fields' values here */ - /* -- end of strings -- */ STRING_LAST /* not used, just an end-of-list marker */ }; @@ -1431,8 +1426,8 @@ struct UserDefined { long proxyport; /* If non-zero, use this port number by default. If the proxy string features a ":[port]" that one will override this. */ - void *out; /* the fetched file goes here */ - void *in; /* the uploaded file is read from here */ + void *out; /* CURLOPT_WRITEDATA */ + void *in; /* CURLOPT_READDATA */ void *writeheader; /* write the header to this if non-NULL */ void *rtp_out; /* write RTP to this if non-NULL */ long use_port; /* which port to use (when not using default) */ @@ -1553,7 +1548,7 @@ struct UserDefined { bool ftp_list_only; /* switch FTP command for listing directories */ bool ftp_use_port; /* use the FTP PORT command */ bool hide_progress; /* don't use the progress meter */ - bool http_fail_on_error; /* fail on HTTP error codes >= 300 */ + bool http_fail_on_error; /* fail on HTTP error codes >= 400 */ bool http_follow_location; /* follow HTTP redirects */ bool http_transfer_encoding; /* request compressed HTTP transfer-encoding */ bool http_disable_hostname_check_before_authentication; @@ -1566,7 +1561,7 @@ struct UserDefined { enum CURL_NETRC_OPTION use_netrc; /* defined in include/curl.h */ bool verbose; /* output verbosity */ - bool krb; /* kerberos connection requested */ + bool krb; /* Kerberos connection requested */ bool reuse_forbid; /* forbidden to be reused, close after use */ bool reuse_fresh; /* do not re-use an existing connection */ bool ftp_use_epsv; /* if EPSV is to be attempted or not */ @@ -1586,6 +1581,7 @@ struct UserDefined { bool connect_only; /* make connection, let application use the socket */ bool ssl_enable_beast; /* especially allow this flaw for interoperability's sake*/ + bool ssl_no_revoke; /* disable SSL certificate revocation checks */ long ssh_auth_types; /* allowed SSH auth types */ bool http_te_skip; /* pass the raw body data to the user, even when transfer-encoded (chunked, compressed) */ @@ -1596,7 +1592,7 @@ struct UserDefined { bool proxy_transfer_mode; /* set transfer mode (;type=<a|i>) when doing FTP via an HTTP proxy */ char *str[STRING_LAST]; /* array of strings, pointing to allocated memory */ - unsigned int scope; /* address scope for IPv6 */ + unsigned int scope_id; /* Scope id for IPv6 */ long allowed_protocols; long redir_protocols; #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) @@ -1627,7 +1623,9 @@ struct UserDefined { bool ssl_enable_npn; /* TLS NPN extension? */ bool ssl_enable_alpn; /* TLS ALPN extension? */ - + bool path_as_is; /* allow dotdots? */ + bool pipewait; /* wait for pipe/multiplex status before starting a + new connection */ long expect_100_timeout; /* in milliseconds */ }; diff --git a/Utilities/cmcurl/lib/version.c b/Utilities/cmcurl/lib/version.c index 788f3e9..1727c5a 100644 --- a/Utilities/cmcurl/lib/version.c +++ b/Utilities/cmcurl/lib/version.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -26,9 +26,7 @@ #include "urldata.h" #include "vtls/vtls.h" #include "http2.h" - -#define _MPRINTF_REPLACE /* use the internal *printf() functions */ -#include <curl/mprintf.h> +#include "curl_printf.h" #ifdef USE_ARES # if defined(CURL_STATICLIB) && !defined(CARES_STATICLIB) && \ @@ -216,6 +214,14 @@ static const char * const protocols[] = { #ifdef USE_LIBSSH2 "sftp", #endif +#if !defined(CURL_DISABLE_SMB) && defined(USE_NTLM) && \ + (CURL_SIZEOF_CURL_OFF_T > 4) && \ + (!defined(USE_WINDOWS_SSPI) || defined(USE_WIN32_CRYPTO)) + "smb", +# ifdef USE_SSL + "smbs", +# endif +#endif #ifndef CURL_DISABLE_SMTP "smtp", #endif @@ -247,12 +253,16 @@ static curl_version_info_data version_info = { #ifdef USE_NTLM | CURL_VERSION_NTLM #endif -#if defined(USE_NTLM) && defined(NTLM_WB_ENABLED) +#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \ + defined(NTLM_WB_ENABLED) | CURL_VERSION_NTLM_WB #endif #ifdef USE_SPNEGO | CURL_VERSION_SPNEGO #endif +#ifdef USE_KERBEROS5 + | CURL_VERSION_KERBEROS5 +#endif #ifdef HAVE_GSSAPI | CURL_VERSION_GSSAPI #endif @@ -284,6 +294,9 @@ static curl_version_info_data version_info = { #if defined(USE_NGHTTP2) | CURL_VERSION_HTTP2 #endif +#if defined(USE_UNIX_SOCKETS) + | CURL_VERSION_UNIX_SOCKETS +#endif , NULL, /* ssl_version */ 0, /* ssl_version_num, this is kept at zero */ diff --git a/Utilities/cmcurl/lib/vtls/axtls.c b/Utilities/cmcurl/lib/vtls/axtls.c index 1b577b1..1038432 100644 --- a/Utilities/cmcurl/lib/vtls/axtls.c +++ b/Utilities/cmcurl/lib/vtls/axtls.c @@ -6,7 +6,7 @@ * \___|\___/|_| \_\_____| * * Copyright (C) 2010, DirecTV, Contact: Eric Hu, <ehu@directv.com>. - * Copyright (C) 2010 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2010 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -29,6 +29,7 @@ #include "curl_setup.h" #ifdef USE_AXTLS +#include <axTLS/config.h> #include <axTLS/ssl.h> #include "axtls.h" @@ -38,13 +39,13 @@ #include "parsedate.h" #include "connect.h" /* for the connect timeout */ #include "select.h" -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> -#include "curl_memory.h" +#include "curl_printf.h" +#include "hostcheck.h" #include <unistd.h> -/* The last #include file should be: */ + +/* The last #include files should be: */ +#include "curl_memory.h" #include "memdebug.h" -#include "hostcheck.h" /* Global axTLS init, called from Curl_ssl_init() */ @@ -463,9 +464,11 @@ Curl_axtls_connect(struct connectdata *conn, int sockindex) { + struct SessionHandle *data = conn->data; CURLcode conn_step = connect_prep(conn, sockindex); int ssl_fcn_return; SSL *ssl = conn->ssl[sockindex].ssl; + long timeout_ms; if(conn_step != CURLE_OK) { Curl_axtls_close(conn, sockindex); @@ -474,14 +477,23 @@ Curl_axtls_connect(struct connectdata *conn, /* Check to make sure handshake was ok. */ while(ssl_handshake_status(ssl) != SSL_OK) { + /* check allowed time left */ + timeout_ms = Curl_timeleft(data, NULL, TRUE); + + if(timeout_ms < 0) { + /* no need to continue if time already is up */ + failf(data, "SSL connection timeout"); + return CURLE_OPERATION_TIMEDOUT; + } + ssl_fcn_return = ssl_read(ssl, NULL); if(ssl_fcn_return < 0) { Curl_axtls_close(conn, sockindex); ssl_display_error(ssl_fcn_return); /* goes to stdout. */ return map_error_to_curl(ssl_fcn_return); } + /* TODO: avoid polling */ usleep(10000); - /* TODO: check for timeout as this could hang indefinitely otherwise */ } infof (conn->data, "handshake completed successfully\n"); @@ -515,12 +527,6 @@ static ssize_t axtls_send(struct connectdata *conn, return rc; } -void Curl_axtls_close_all(struct SessionHandle *data) -{ - (void)data; - infof(data, " Curl_axtls_close_all\n"); -} - void Curl_axtls_close(struct connectdata *conn, int sockindex) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; @@ -677,7 +683,7 @@ int Curl_axtls_random(struct SessionHandle *data, * race condition is that some global resources will leak. */ RNG_initialize(); } - get_random(length, entropy); + get_random((int)length, entropy); return 0; } diff --git a/Utilities/cmcurl/lib/vtls/axtls.h b/Utilities/cmcurl/lib/vtls/axtls.h index 0459cf2..223ecb8 100644 --- a/Utilities/cmcurl/lib/vtls/axtls.h +++ b/Utilities/cmcurl/lib/vtls/axtls.h @@ -7,8 +7,8 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2010, DirecTV - * contact: Eric Hu <ehu@directv.com> + * Copyright (C) 2010, DirecTV, Contact: Eric Hu <ehu@directv.com> + * Copyright (C) 2010 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -35,10 +35,6 @@ CURLcode Curl_axtls_connect_nonblocking( int sockindex, bool *done); -/* tell axTLS to close down all open information regarding connections (and - thus session ID caching etc) */ -void Curl_axtls_close_all(struct SessionHandle *data); - /* close a SSL connection */ void Curl_axtls_close(struct connectdata *conn, int sockindex); @@ -50,23 +46,26 @@ int Curl_axtls_random(struct SessionHandle *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 Curl_axtls_close_all +#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) (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_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) (x=x, y=y, 0) +#define curlssl_data_pending(x,y) ((void)x, (void)y, 0) #define curlssl_random(x,y,z) Curl_axtls_random(x,y,z) -#define CURL_SSL_BACKEND CURLSSLBACKEND_AXTLS + #endif /* USE_AXTLS */ #endif /* HEADER_CURL_AXTLS_H */ diff --git a/Utilities/cmcurl/lib/vtls/cyassl.c b/Utilities/cmcurl/lib/vtls/cyassl.c index 9b5c7c6..3ded7f1 100644 --- a/Utilities/cmcurl/lib/vtls/cyassl.c +++ b/Utilities/cmcurl/lib/vtls/cyassl.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -30,6 +30,20 @@ #ifdef USE_CYASSL +#define WOLFSSL_OPTIONS_IGNORE_SYS +/* CyaSSL's version.h, which should contain only the version, should come +before all other CyaSSL includes and be immediately followed by build config +aka options.h. http://curl.haxx.se/mail/lib-2015-04/0069.html */ +#include <cyassl/version.h> +#if defined(HAVE_CYASSL_OPTIONS_H) && (LIBCYASSL_VERSION_HEX > 0x03004008) +#if defined(CYASSL_API) || defined(WOLFSSL_API) +/* Safety measure. If either is defined some API include was already included +and that's a problem since options.h hasn't been included yet. */ +#error "CyaSSL API was included before the CyaSSL build options." +#endif +#include <cyassl/options.h> +#endif + #ifdef HAVE_LIMITS_H #include <limits.h> #endif @@ -43,10 +57,8 @@ #include "connect.h" /* for the connect timeout */ #include "select.h" #include "rawstr.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> -#include "curl_memory.h" +#include "x509asn1.h" +#include "curl_printf.h" #include <cyassl/ssl.h> #ifdef HAVE_CYASSL_ERROR_SSL_H @@ -55,10 +67,16 @@ #include <cyassl/error.h> #endif #include <cyassl/ctaocrypt/random.h> +#include <cyassl/ctaocrypt/sha256.h> -/* The last #include file should be: */ +/* The last #include files should be: */ +#include "curl_memory.h" #include "memdebug.h" +#if LIBCYASSL_VERSION_HEX < 0x02007002 /* < 2.7.2 */ +#define CYASSL_MAX_ERROR_SZ 80 +#endif + static Curl_recv cyassl_recv; static Curl_send cyassl_send; @@ -82,46 +100,58 @@ static CURLcode cyassl_connect_step1(struct connectdata *conn, int sockindex) { + char error_buffer[CYASSL_MAX_ERROR_SZ]; struct SessionHandle *data = conn->data; struct ssl_connect_data* conssl = &conn->ssl[sockindex]; SSL_METHOD* req_method = NULL; void* ssl_sessionid = NULL; curl_socket_t sockfd = conn->sock[sockindex]; +#ifdef HAVE_SNI + bool sni = FALSE; +#define use_sni(x) sni = (x) +#else +#define use_sni(x) Curl_nop_stmt +#endif if(conssl->state == ssl_connection_complete) return CURLE_OK; - /* CyaSSL doesn't support SSLv2 */ - if(data->set.ssl.version == CURL_SSLVERSION_SSLv2) { - failf(data, "CyaSSL does not support SSLv2"); - return CURLE_SSL_CONNECT_ERROR; - } - /* check to see if we've been told to use an explicit SSL/TLS version */ switch(data->set.ssl.version) { case CURL_SSLVERSION_DEFAULT: - /* we try to figure out version */ - req_method = SSLv23_client_method(); - break; case CURL_SSLVERSION_TLSv1: - infof(data, "CyaSSL cannot be configured to use TLS 1.0-1.2, " +#if LIBCYASSL_VERSION_HEX >= 0x03003000 /* >= 3.3.0 */ + /* minimum protocol version is set later after the CTX object is created */ + req_method = SSLv23_client_method(); +#else + infof(data, "CyaSSL <3.3.0 cannot be configured to use TLS 1.0-1.2, " "TLS 1.0 is used exclusively\n"); req_method = TLSv1_client_method(); +#endif + use_sni(TRUE); break; case CURL_SSLVERSION_TLSv1_0: req_method = TLSv1_client_method(); + use_sni(TRUE); break; case CURL_SSLVERSION_TLSv1_1: req_method = TLSv1_1_client_method(); + use_sni(TRUE); break; case CURL_SSLVERSION_TLSv1_2: req_method = TLSv1_2_client_method(); + use_sni(TRUE); break; case CURL_SSLVERSION_SSLv3: req_method = SSLv3_client_method(); + use_sni(FALSE); break; + case CURL_SSLVERSION_SSLv2: + failf(data, "CyaSSL does not support SSLv2"); + return CURLE_SSL_CONNECT_ERROR; default: - req_method = TLSv1_client_method(); + failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); + return CURLE_SSL_CONNECT_ERROR; } if(!req_method) { @@ -138,15 +168,36 @@ cyassl_connect_step1(struct connectdata *conn, return CURLE_OUT_OF_MEMORY; } + switch(data->set.ssl.version) { + case CURL_SSLVERSION_DEFAULT: + case CURL_SSLVERSION_TLSv1: +#if LIBCYASSL_VERSION_HEX > 0x03004006 /* > 3.4.6 */ + /* Versions 3.3.0 to 3.4.6 we know the minimum protocol version is whatever + minimum version of TLS was built in and at least TLS 1.0. For later library + versions that could change (eg TLS 1.0 built in but defaults to TLS 1.1) so + we have this short circuit evaluation to find the minimum supported TLS + 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)) { + failf(data, "SSL: couldn't set the minimum protocol version"); + return CURLE_SSL_CONNECT_ERROR; + } +#endif + break; + } + #ifndef NO_FILESYSTEM /* load trusted cacert */ if(data->set.str[STRING_SSL_CAFILE]) { - if(!SSL_CTX_load_verify_locations(conssl->ctx, - data->set.str[STRING_SSL_CAFILE], - data->set.str[STRING_SSL_CAPATH])) { + if(1 != SSL_CTX_load_verify_locations(conssl->ctx, + data->set.str[STRING_SSL_CAFILE], + data->set.str[STRING_SSL_CAPATH])) { if(data->set.ssl.verifypeer) { /* Fail if we insist on successfully verifying the server. */ - failf(data,"error setting certificate verify locations:\n" + failf(data, "error setting certificate verify locations:\n" " CAfile: %s\n CApath: %s", data->set.str[STRING_SSL_CAFILE]? data->set.str[STRING_SSL_CAFILE]: "none", @@ -192,11 +243,7 @@ cyassl_connect_step1(struct connectdata *conn, return CURLE_SSL_CONNECT_ERROR; } } -#else - if(CyaSSL_no_filesystem_verify(conssl->ctx)!= SSL_SUCCESS) { - return CURLE_SSL_CONNECT_ERROR; - } -#endif /* NO_FILESYSTEM */ +#endif /* !NO_FILESYSTEM */ /* SSL always tries to verify the peer, this only says whether it should * fail to connect if the verification fails, or if it should continue @@ -206,6 +253,46 @@ cyassl_connect_step1(struct connectdata *conn, data->set.ssl.verifypeer?SSL_VERIFY_PEER:SSL_VERIFY_NONE, NULL); +#ifdef HAVE_SNI + if(sni) { + struct in_addr addr4; +#ifdef ENABLE_IPV6 + struct in6_addr addr6; +#endif + size_t hostname_len = strlen(conn->host.name); + if((hostname_len < USHRT_MAX) && + (0 == Curl_inet_pton(AF_INET, conn->host.name, &addr4)) && +#ifdef ENABLE_IPV6 + (0 == Curl_inet_pton(AF_INET6, conn->host.name, &addr6)) && +#endif + (CyaSSL_CTX_UseSNI(conssl->ctx, CYASSL_SNI_HOST_NAME, conn->host.name, + (unsigned short)hostname_len) != 1)) { + infof(data, "WARNING: failed to configure server name indication (SNI) " + "TLS extension\n"); + } + } +#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, + data->set.ssl.fsslctxp); + if(result) { + failf(data, "error signaled by ssl ctx callback"); + return result; + } + } +#ifdef NO_FILESYSTEM + else if(data->set.ssl.verifypeer) { + failf(data, "SSL: Certificates couldn't be loaded because CyaSSL was built" + " with \"no filesystem\". Either disable peer verification" + " (insecure) or if you are building an application with libcurl you" + " can load certificates via CURLOPT_SSL_CTX_FUNCTION."); + return CURLE_SSL_CONNECT_ERROR; + } +#endif + /* Let's make an SSL structure */ if(conssl->handle) SSL_free(conssl->handle); @@ -220,7 +307,7 @@ cyassl_connect_step1(struct connectdata *conn, /* we got a session id, use it! */ if(!SSL_set_session(conssl->handle, ssl_sessionid)) { failf(data, "SSL: SSL_set_session failed: %s", - ERR_error_string(SSL_get_error(conssl->handle, 0),NULL)); + ERR_error_string(SSL_get_error(conssl->handle, 0), error_buffer)); return CURLE_SSL_CONNECT_ERROR; } /* Informational message */ @@ -246,9 +333,6 @@ cyassl_connect_step2(struct connectdata *conn, struct SessionHandle *data = conn->data; struct ssl_connect_data* conssl = &conn->ssl[sockindex]; - infof(data, "CyaSSL: Connecting to %s:%d\n", - conn->host.name, conn->remote_port); - conn->recv[sockindex] = cyassl_recv; conn->send[sockindex] = cyassl_send; @@ -261,7 +345,7 @@ cyassl_connect_step2(struct connectdata *conn, ret = SSL_connect(conssl->handle); if(ret != 1) { - char error_buffer[80]; + char error_buffer[CYASSL_MAX_ERROR_SZ]; int detail = SSL_get_error(conssl->handle, ret); if(SSL_ERROR_WANT_READ == detail) { @@ -321,6 +405,44 @@ cyassl_connect_step2(struct connectdata *conn, } } + if(data->set.str[STRING_SSL_PINNEDPUBLICKEY]) { + X509 *x509; + const char *x509_der; + int x509_der_len; + curl_X509certificate x509_parsed; + curl_asn1Element *pubkey; + CURLcode result; + + x509 = SSL_get_peer_certificate(conssl->handle); + if(!x509) { + failf(data, "SSL: failed retrieving server certificate"); + return CURLE_SSL_PINNEDPUBKEYNOTMATCH; + } + + x509_der = (const char *)CyaSSL_X509_get_der(x509, &x509_der_len); + if(!x509_der) { + failf(data, "SSL: failed retrieving ASN.1 server certificate"); + return CURLE_SSL_PINNEDPUBKEYNOTMATCH; + } + + memset(&x509_parsed, 0, sizeof x509_parsed); + Curl_parseX509(&x509_parsed, x509_der, x509_der + x509_der_len); + + pubkey = &x509_parsed.subjectPublicKeyInfo; + if(!pubkey->header || pubkey->end <= pubkey->header) { + failf(data, "SSL: failed retrieving public key from server certificate"); + return CURLE_SSL_PINNEDPUBKEYNOTMATCH; + } + + result = Curl_pin_peer_pubkey(data->set.str[STRING_SSL_PINNEDPUBLICKEY], + (const unsigned char *)pubkey->header, + (size_t)(pubkey->end - pubkey->header)); + if(result) { + failf(data, "SSL: public key does not match pinned public key!"); + return result; + } + } + conssl->connecting_state = ssl_connect_3; infof(data, "SSL connected\n"); @@ -332,11 +454,11 @@ static CURLcode cyassl_connect_step3(struct connectdata *conn, int sockindex) { - CURLcode retcode = CURLE_OK; + CURLcode result = CURLE_OK; void *old_ssl_sessionid=NULL; struct SessionHandle *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - int incache; + bool incache; SSL_SESSION *our_ssl_sessionid; DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); @@ -351,18 +473,19 @@ cyassl_connect_step3(struct connectdata *conn, incache = FALSE; } } + if(!incache) { - retcode = Curl_ssl_addsessionid(conn, our_ssl_sessionid, - 0 /* unknown size */); - if(retcode) { + result = Curl_ssl_addsessionid(conn, our_ssl_sessionid, + 0 /* unknown size */); + if(result) { failf(data, "failed to store ssl session"); - return retcode; + return result; } } connssl->connecting_state = ssl_connect_done; - return retcode; + return result; } @@ -372,7 +495,7 @@ static ssize_t cyassl_send(struct connectdata *conn, size_t len, CURLcode *curlcode) { - char error_buffer[80]; + 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); @@ -396,11 +519,6 @@ static ssize_t cyassl_send(struct connectdata *conn, return rc; } -void Curl_cyassl_close_all(struct SessionHandle *data) -{ - (void)data; -} - void Curl_cyassl_close(struct connectdata *conn, int sockindex) { struct ssl_connect_data *conssl = &conn->ssl[sockindex]; @@ -422,7 +540,7 @@ static ssize_t cyassl_recv(struct connectdata *conn, size_t buffersize, CURLcode *curlcode) { - char error_buffer[80]; + 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); @@ -458,7 +576,9 @@ void Curl_cyassl_session_free(void *ptr) size_t Curl_cyassl_version(char *buffer, size_t size) { -#ifdef CYASSL_VERSION +#ifdef WOLFSSL_VERSION + return snprintf(buffer, size, "wolfSSL/%s", WOLFSSL_VERSION); +#elif defined(CYASSL_VERSION) return snprintf(buffer, size, "CyaSSL/%s", CYASSL_VERSION); #else return snprintf(buffer, size, "CyaSSL/%s", "<1.8.8"); @@ -468,10 +588,7 @@ size_t Curl_cyassl_version(char *buffer, size_t size) int Curl_cyassl_init(void) { - if(CyaSSL_Init() == 0) - return 1; - - return -1; + return (CyaSSL_Init() == SSL_SUCCESS); } @@ -507,7 +624,7 @@ cyassl_connect_common(struct connectdata *conn, bool nonblocking, bool *done) { - CURLcode retcode; + CURLcode result; struct SessionHandle *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; curl_socket_t sockfd = conn->sock[sockindex]; @@ -529,9 +646,10 @@ cyassl_connect_common(struct connectdata *conn, failf(data, "SSL connection timeout"); return CURLE_OPERATION_TIMEDOUT; } - retcode = cyassl_connect_step1(conn, sockindex); - if(retcode) - return retcode; + + result = cyassl_connect_step1(conn, sockindex); + if(result) + return result; } while(ssl_connect_2 == connssl->connecting_state || @@ -583,22 +701,21 @@ cyassl_connect_common(struct connectdata *conn, * ensuring that a client using select() or epoll() will always * have a valid fdset to wait on. */ - retcode = cyassl_connect_step2(conn, sockindex); - if(retcode || (nonblocking && - (ssl_connect_2 == connssl->connecting_state || - ssl_connect_2_reading == connssl->connecting_state || - ssl_connect_2_writing == connssl->connecting_state))) - return retcode; - + result = cyassl_connect_step2(conn, sockindex); + if(result || (nonblocking && + (ssl_connect_2 == connssl->connecting_state || + ssl_connect_2_reading == connssl->connecting_state || + ssl_connect_2_writing == connssl->connecting_state))) + return result; } /* repeat step2 until all transactions are done. */ - if(ssl_connect_3==connssl->connecting_state) { - retcode = cyassl_connect_step3(conn, sockindex); - if(retcode) - return retcode; + if(ssl_connect_3 == connssl->connecting_state) { + result = cyassl_connect_step3(conn, sockindex); + if(result) + return result; } - if(ssl_connect_done==connssl->connecting_state) { + if(ssl_connect_done == connssl->connecting_state) { connssl->state = ssl_connection_complete; conn->recv[sockindex] = cyassl_recv; conn->send[sockindex] = cyassl_send; @@ -627,12 +744,12 @@ CURLcode Curl_cyassl_connect(struct connectdata *conn, int sockindex) { - CURLcode retcode; + CURLcode result; bool done = FALSE; - retcode = cyassl_connect_common(conn, sockindex, FALSE, &done); - if(retcode) - return retcode; + result = cyassl_connect_common(conn, sockindex, FALSE, &done); + if(result) + return result; DEBUGASSERT(done); @@ -647,9 +764,23 @@ int Curl_cyassl_random(struct SessionHandle *data, (void)data; if(InitRng(&rng)) return 1; - if(RNG_GenerateBlock(&rng, entropy, length)) + if(length > UINT_MAX) + return 1; + if(RNG_GenerateBlock(&rng, entropy, (unsigned)length)) return 1; return 0; } +void Curl_cyassl_sha256sum(const unsigned char *tmp, /* input */ + size_t tmplen, + unsigned char *sha256sum /* output */, + size_t unused) +{ + Sha256 SHA256pw; + (void)unused; + InitSha256(&SHA256pw); + Sha256Update(&SHA256pw, tmp, tmplen); + Sha256Final(&SHA256pw, sha256sum); +} + #endif diff --git a/Utilities/cmcurl/lib/vtls/cyassl.h b/Utilities/cmcurl/lib/vtls/cyassl.h index b10b607..167de74 100644 --- a/Utilities/cmcurl/lib/vtls/cyassl.h +++ b/Utilities/cmcurl/lib/vtls/cyassl.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -26,13 +26,9 @@ #ifdef USE_CYASSL CURLcode Curl_cyassl_connect(struct connectdata *conn, int sockindex); -bool Curl_cyassl_data_pending(const struct connectdata* conn,int connindex); +bool Curl_cyassl_data_pending(const struct connectdata* conn, int connindex); int Curl_cyassl_shutdown(struct connectdata* conn, int sockindex); -/* tell CyaSSL to close down all open information regarding connections (and - thus session ID caching etc) */ -void Curl_cyassl_close_all(struct SessionHandle *data); - /* close a SSL connection */ void Curl_cyassl_close(struct connectdata *conn, int sockindex); @@ -46,6 +42,16 @@ CURLcode Curl_cyassl_connect_nonblocking(struct connectdata *conn, int Curl_cyassl_random(struct SessionHandle *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 Schannel */ +#define CURL_SSL_BACKEND CURLSSLBACKEND_CYASSL + +/* this backend supports CURLOPT_SSL_CTX_* */ +#define have_curlssl_ssl_ctx 1 /* API setup for CyaSSL */ #define curlssl_init Curl_cyassl_init @@ -53,17 +59,17 @@ int Curl_cyassl_random(struct SessionHandle *data, #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 Curl_cyassl_close_all +#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) (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_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) (x=x, -1) +#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 CURL_SSL_BACKEND CURLSSLBACKEND_CYASSL +#define curlssl_sha256sum(a,b,c,d) Curl_cyassl_sha256sum(a,b,c,d) #endif /* USE_CYASSL */ #endif /* HEADER_CURL_CYASSL_H */ diff --git a/Utilities/cmcurl/lib/vtls/curl_darwinssl.c b/Utilities/cmcurl/lib/vtls/darwinssl.c index f229c6f..03adcef 100644 --- a/Utilities/cmcurl/lib/vtls/curl_darwinssl.c +++ b/Utilities/cmcurl/lib/vtls/darwinssl.c @@ -6,7 +6,7 @@ * \___|\___/|_| \_\_____| * * Copyright (C) 2012 - 2014, Nick Zitzmann, <nickzman@gmail.com>. - * Copyright (C) 2012 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2012 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -86,6 +86,7 @@ #define CURL_SUPPORT_MAC_10_6 0 #define CURL_SUPPORT_MAC_10_7 0 #define CURL_SUPPORT_MAC_10_8 0 +#define CURL_SUPPORT_MAC_10_9 0 #else #error "The darwinssl back-end requires iOS or OS X." @@ -101,10 +102,8 @@ #include "connect.h" #include "select.h" #include "vtls.h" -#include "curl_darwinssl.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> +#include "darwinssl.h" +#include "curl_printf.h" #include "curl_memory.h" /* The last #include file should be: */ @@ -1057,10 +1056,8 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, #if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS if(SSLSetProtocolVersionMax != NULL) { switch(data->set.ssl.version) { - case CURL_SSLVERSION_DEFAULT: default: - (void)SSLSetProtocolVersionMin(connssl->ssl_ctx, kSSLProtocol3); - (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kTLSProtocol12); - break; + default: + case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: (void)SSLSetProtocolVersionMin(connssl->ssl_ctx, kTLSProtocol1); (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kTLSProtocol12); @@ -1078,7 +1075,11 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kTLSProtocol12); break; case CURL_SSLVERSION_SSLv3: - (void)SSLSetProtocolVersionMin(connssl->ssl_ctx, kSSLProtocol3); + err = SSLSetProtocolVersionMin(connssl->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); break; case CURL_SSLVERSION_SSLv2: @@ -1096,20 +1097,8 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, kSSLProtocolAll, false); switch (data->set.ssl.version) { - case CURL_SSLVERSION_DEFAULT: default: - (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, - kSSLProtocol3, - true); - (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, - kTLSProtocol1, - true); - (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, - kTLSProtocol11, - true); - (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, - kTLSProtocol12, - true); - break; + default: + case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, kTLSProtocol1, @@ -1137,9 +1126,13 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, true); break; case CURL_SSLVERSION_SSLv3: - (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, + err = SSLSetProtocolVersionEnabled(connssl->ssl_ctx, kSSLProtocol3, true); + if(err != noErr) { + failf(data, "Your version of the OS does not support SSLv3"); + return CURLE_SSL_CONNECT_ERROR; + } break; case CURL_SSLVERSION_SSLv2: err = SSLSetProtocolVersionEnabled(connssl->ssl_ctx, @@ -1158,13 +1151,6 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, switch(data->set.ssl.version) { default: case CURL_SSLVERSION_DEFAULT: - (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, - kSSLProtocol3, - true); - (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, - kTLSProtocol1, - true); - break; case CURL_SSLVERSION_TLSv1: case CURL_SSLVERSION_TLSv1_0: (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, @@ -1187,9 +1173,13 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, } break; case CURL_SSLVERSION_SSLv3: - (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, + err = SSLSetProtocolVersionEnabled(connssl->ssl_ctx, kSSLProtocol3, true); + if(err != noErr) { + failf(data, "Your version of the OS does not support SSLv3"); + return CURLE_SSL_CONNECT_ERROR; + } break; } #endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */ @@ -1469,14 +1459,17 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, #if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 /* We want to enable 1/n-1 when using a CBC cipher unless the user specifically doesn't want us doing that: */ - if(SSLSetSessionOption != NULL) + if(SSLSetSessionOption != NULL) { SSLSetSessionOption(connssl->ssl_ctx, kSSLSessionOptionSendOneByteRecord, !data->set.ssl_enable_beast); + SSLSetSessionOption(connssl->ssl_ctx, kSSLSessionOptionFalseStart, + data->set.ssl.falsestart); /* false start support */ + } #endif /* CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 */ /* Check if there's a cached ID we can/should use here! */ if(!Curl_ssl_getsessionid(conn, (void **)&ssl_sessionid, - &ssl_sessionid_len)) { + &ssl_sessionid_len)) { /* we got a session id, use it! */ err = SSLSetPeerID(connssl->ssl_ctx, ssl_sessionid, ssl_sessionid_len); if(err != noErr) { @@ -1489,20 +1482,23 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, /* If there isn't one, then let's make one up! This has to be done prior to starting the handshake. */ else { - CURLcode retcode; + CURLcode result; + ssl_sessionid = + aprintf("%s:%d:%d:%s:%hu", data->set.str[STRING_SSL_CAFILE], + data->set.ssl.verifypeer, data->set.ssl.verifyhost, + conn->host.name, conn->remote_port); + ssl_sessionid_len = strlen(ssl_sessionid); - ssl_sessionid = malloc(256*sizeof(char)); - ssl_sessionid_len = snprintf(ssl_sessionid, 256, "curl:%s:%hu", - conn->host.name, conn->remote_port); err = SSLSetPeerID(connssl->ssl_ctx, ssl_sessionid, ssl_sessionid_len); if(err != noErr) { failf(data, "SSL: SSLSetPeerID() failed: OSStatus %d", err); return CURLE_SSL_CONNECT_ERROR; } - retcode = Curl_ssl_addsessionid(conn, ssl_sessionid, ssl_sessionid_len); - if(retcode!= CURLE_OK) { + + result = Curl_ssl_addsessionid(conn, ssl_sessionid, ssl_sessionid_len); + if(result) { failf(data, "failed to store ssl session"); - return retcode; + return result; } } @@ -2081,7 +2077,7 @@ darwinssl_connect_common(struct connectdata *conn, bool nonblocking, bool *done) { - CURLcode retcode; + CURLcode result; struct SessionHandle *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; curl_socket_t sockfd = conn->sock[sockindex]; @@ -2103,9 +2099,10 @@ darwinssl_connect_common(struct connectdata *conn, failf(data, "SSL connection timeout"); return CURLE_OPERATION_TIMEDOUT; } - retcode = darwinssl_connect_step1(conn, sockindex); - if(retcode) - return retcode; + + result = darwinssl_connect_step1(conn, sockindex); + if(result) + return result; } while(ssl_connect_2 == connssl->connecting_state || @@ -2122,8 +2119,8 @@ darwinssl_connect_common(struct connectdata *conn, } /* if ssl is expecting something, check if it's available. */ - if(connssl->connecting_state == ssl_connect_2_reading - || connssl->connecting_state == ssl_connect_2_writing) { + if(connssl->connecting_state == ssl_connect_2_reading || + connssl->connecting_state == ssl_connect_2_writing) { curl_socket_t writefd = ssl_connect_2_writing == connssl->connecting_state?sockfd:CURL_SOCKET_BAD; @@ -2156,23 +2153,23 @@ darwinssl_connect_common(struct connectdata *conn, * before step2 has completed while ensuring that a client using select() * or epoll() will always have a valid fdset to wait on. */ - retcode = darwinssl_connect_step2(conn, sockindex); - if(retcode || (nonblocking && - (ssl_connect_2 == connssl->connecting_state || - ssl_connect_2_reading == connssl->connecting_state || - ssl_connect_2_writing == connssl->connecting_state))) - return retcode; + result = darwinssl_connect_step2(conn, sockindex); + if(result || (nonblocking && + (ssl_connect_2 == connssl->connecting_state || + ssl_connect_2_reading == connssl->connecting_state || + ssl_connect_2_writing == connssl->connecting_state))) + return result; } /* repeat step2 until all transactions are done. */ - if(ssl_connect_3==connssl->connecting_state) { - retcode = darwinssl_connect_step3(conn, sockindex); - if(retcode) - return retcode; + if(ssl_connect_3 == connssl->connecting_state) { + result = darwinssl_connect_step3(conn, sockindex); + if(result) + return result; } - if(ssl_connect_done==connssl->connecting_state) { + if(ssl_connect_done == connssl->connecting_state) { connssl->state = ssl_connection_complete; conn->recv[sockindex] = darwinssl_recv; conn->send[sockindex] = darwinssl_send; @@ -2199,13 +2196,13 @@ CURLcode Curl_darwinssl_connect(struct connectdata *conn, int sockindex) { - CURLcode retcode; + CURLcode result; bool done = FALSE; - retcode = darwinssl_connect_common(conn, sockindex, FALSE, &done); + result = darwinssl_connect_common(conn, sockindex, FALSE, &done); - if(retcode) - return retcode; + if(result) + return result; DEBUGASSERT(done); @@ -2233,12 +2230,6 @@ void Curl_darwinssl_close(struct connectdata *conn, int sockindex) connssl->ssl_sockfd = 0; } -void Curl_darwinssl_close_all(struct SessionHandle *data) -{ - /* SecureTransport doesn't separate sessions from contexts, so... */ - (void)data; -} - int Curl_darwinssl_shutdown(struct connectdata *conn, int sockindex) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; @@ -2376,6 +2367,14 @@ void Curl_darwinssl_md5sum(unsigned char *tmp, /* input */ (void)CC_MD5(tmp, (CC_LONG)tmplen, md5sum); } +bool Curl_darwinssl_false_start(void) { +#if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 + if(SSLSetSessionOption != NULL) + return TRUE; +#endif + return FALSE; +} + static ssize_t darwinssl_send(struct connectdata *conn, int sockindex, const void *mem, diff --git a/Utilities/cmcurl/lib/vtls/curl_darwinssl.h b/Utilities/cmcurl/lib/vtls/darwinssl.h index f5c03d8..3bb69c0 100644 --- a/Utilities/cmcurl/lib/vtls/curl_darwinssl.h +++ b/Utilities/cmcurl/lib/vtls/darwinssl.h @@ -8,6 +8,7 @@ * \___|\___/|_| \_\_____| * * Copyright (C) 2012 - 2014, Nick Zitzmann, <nickzman@gmail.com>. + * Copyright (C) 2012 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -31,9 +32,6 @@ CURLcode Curl_darwinssl_connect_nonblocking(struct connectdata *conn, int sockindex, bool *done); -/* this function doesn't actually do anything */ -void Curl_darwinssl_close_all(struct SessionHandle *data); - /* close a SSL connection */ void Curl_darwinssl_close(struct connectdata *conn, int sockindex); @@ -50,9 +48,10 @@ void Curl_darwinssl_md5sum(unsigned char *tmp, /* input */ size_t tmplen, unsigned char *md5sum, /* output */ size_t md5len); +bool Curl_darwinssl_false_start(void); -/* this backend provides these functions: */ -#define have_curlssl_md5sum 1 +/* Set the API backend definition to SecureTransport */ +#define CURL_SSL_BACKEND CURLSSLBACKEND_DARWINSSL /* API setup for SecureTransport */ #define curlssl_init() (1) @@ -60,18 +59,18 @@ void Curl_darwinssl_md5sum(unsigned char *tmp, /* input */ #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 Curl_darwinssl_close_all +#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) (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_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) Curl_darwinssl_random(y,z) +#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 CURL_SSL_BACKEND CURLSSLBACKEND_DARWINSSL +#define curlssl_false_start() Curl_darwinssl_false_start() #endif /* USE_DARWINSSL */ #endif /* HEADER_CURL_DARWINSSL_H */ diff --git a/Utilities/cmcurl/lib/vtls/gskit.c b/Utilities/cmcurl/lib/vtls/gskit.c index 0f8b08f..d884bd4 100644 --- a/Utilities/cmcurl/lib/vtls/gskit.c +++ b/Utilities/cmcurl/lib/vtls/gskit.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -74,9 +74,7 @@ #include "select.h" #include "strequal.h" #include "x509asn1.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> +#include "curl_printf.h" #include "curl_memory.h" /* The last #include file should be: */ @@ -134,8 +132,12 @@ static const gskit_cipher ciphertable[] = { CURL_GSKPROTO_TLSV10_MASK | CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK }, { "null-sha256", "3B", CURL_GSKPROTO_TLSV12_MASK }, - { "aes128-sha256", "3D", CURL_GSKPROTO_TLSV12_MASK }, + { "aes128-sha256", "3C", CURL_GSKPROTO_TLSV12_MASK }, { "aes256-sha256", "3D", CURL_GSKPROTO_TLSV12_MASK }, + { "aes128-gcm-sha256", + "9C", CURL_GSKPROTO_TLSV12_MASK }, + { "aes256-gcm-sha384", + "9D", CURL_GSKPROTO_TLSV12_MASK }, { "rc4-md5", "1", CURL_GSKPROTO_SSLV2_MASK }, { "exp-rc4-md5", "2", CURL_GSKPROTO_SSLV2_MASK }, { "rc2-md5", "3", CURL_GSKPROTO_SSLV2_MASK }, @@ -164,8 +166,6 @@ static bool is_separator(char c) static CURLcode gskit_status(struct SessionHandle *data, int rc, const char *procname, CURLcode defcode) { - CURLcode cc; - /* Process GSKit status and map it to a CURLcode. */ switch (rc) { case GSK_OK: @@ -298,7 +298,7 @@ static CURLcode set_ciphers(struct SessionHandle *data, int i; int l; bool unsupported; - CURLcode cc; + CURLcode result; struct { char *buf; char *ptr; @@ -331,7 +331,7 @@ static CURLcode set_ciphers(struct SessionHandle *data, /* Process each cipher in input string. */ unsupported = FALSE; - cc = CURLE_OK; + result = CURLE_OK; for(;;) { for(clp = cipherlist; *cipherlist && !is_separator(*cipherlist);) cipherlist++; @@ -344,7 +344,7 @@ static CURLcode set_ciphers(struct SessionHandle *data, break; if(!ctp->name) { failf(data, "Unknown cipher %.*s", l, clp); - cc = CURLE_SSL_CIPHER; + result = CURLE_SSL_CIPHER; } else { unsupported |= !(ctp->versions & (CURL_GSKPROTO_SSLV2_MASK | @@ -372,53 +372,53 @@ static CURLcode set_ciphers(struct SessionHandle *data, /* Try to set-up TLSv1.1 and TLSv2.1 ciphers. */ if(*protoflags & CURL_GSKPROTO_TLSV11_MASK) { - cc = set_buffer(data, h, GSK_TLSV11_CIPHER_SPECS, - ciphers[CURL_GSKPROTO_TLSV11].buf, TRUE); - if(cc == CURLE_UNSUPPORTED_PROTOCOL) { - cc = CURLE_OK; + result = set_buffer(data, h, GSK_TLSV11_CIPHER_SPECS, + ciphers[CURL_GSKPROTO_TLSV11].buf, TRUE); + if(result == CURLE_UNSUPPORTED_PROTOCOL) { + result = CURLE_OK; if(unsupported) { failf(data, "TLSv1.1-only ciphers are not yet supported"); - cc = CURLE_SSL_CIPHER; + result = CURLE_SSL_CIPHER; } } } - if(cc == CURLE_OK && (*protoflags & CURL_GSKPROTO_TLSV12_MASK)) { - cc = set_buffer(data, h, GSK_TLSV12_CIPHER_SPECS, - ciphers[CURL_GSKPROTO_TLSV12].buf, TRUE); - if(cc == CURLE_UNSUPPORTED_PROTOCOL) { - cc = CURLE_OK; + if(!result && (*protoflags & CURL_GSKPROTO_TLSV12_MASK)) { + result = set_buffer(data, h, GSK_TLSV12_CIPHER_SPECS, + ciphers[CURL_GSKPROTO_TLSV12].buf, TRUE); + if(result == CURLE_UNSUPPORTED_PROTOCOL) { + result = CURLE_OK; if(unsupported) { failf(data, "TLSv1.2-only ciphers are not yet supported"); - cc = CURLE_SSL_CIPHER; + result = CURLE_SSL_CIPHER; } } } /* Try to set-up TLSv1.0 ciphers. If not successful, concatenate them to the SSLv3 ciphers. OS/400 prior to version 7.1 will understand it. */ - if(cc == CURLE_OK && (*protoflags & CURL_GSKPROTO_TLSV10_MASK)) { - cc = set_buffer(data, h, GSK_TLSV10_CIPHER_SPECS, - ciphers[CURL_GSKPROTO_TLSV10].buf, TRUE); - if(cc == CURLE_UNSUPPORTED_PROTOCOL) { - cc = CURLE_OK; + if(!result && (*protoflags & CURL_GSKPROTO_TLSV10_MASK)) { + result = set_buffer(data, h, GSK_TLSV10_CIPHER_SPECS, + ciphers[CURL_GSKPROTO_TLSV10].buf, TRUE); + if(result == CURLE_UNSUPPORTED_PROTOCOL) { + result = CURLE_OK; strcpy(ciphers[CURL_GSKPROTO_SSLV3].ptr, ciphers[CURL_GSKPROTO_TLSV10].ptr); } } /* Set-up other ciphers. */ - if(cc == CURLE_OK && (*protoflags & CURL_GSKPROTO_SSLV3_MASK)) - cc = set_buffer(data, h, GSK_V3_CIPHER_SPECS, - ciphers[CURL_GSKPROTO_SSLV3].buf, FALSE); - if(cc == CURLE_OK && (*protoflags & CURL_GSKPROTO_SSLV2_MASK)) - cc = set_buffer(data, h, GSK_V2_CIPHER_SPECS, - ciphers[CURL_GSKPROTO_SSLV2].buf, FALSE); + if(!result && (*protoflags & CURL_GSKPROTO_SSLV3_MASK)) + result = set_buffer(data, h, GSK_V3_CIPHER_SPECS, + ciphers[CURL_GSKPROTO_SSLV3].buf, FALSE); + if(!result && (*protoflags & CURL_GSKPROTO_SSLV2_MASK)) + result = set_buffer(data, h, GSK_V2_CIPHER_SPECS, + ciphers[CURL_GSKPROTO_SSLV2].buf, FALSE); /* Clean-up. */ for(i = 0; i < CURL_GSKPROTO_LAST; i++) free(ciphers[i].buf); - return cc; + return result; } @@ -442,7 +442,7 @@ static CURLcode init_environment(struct SessionHandle *data, const char *password) { int rc; - CURLcode c; + CURLcode result; gsk_handle h; /* Creates the GSKit environment. */ @@ -458,29 +458,29 @@ static CURLcode init_environment(struct SessionHandle *data, return CURLE_SSL_CONNECT_ERROR; } - c = set_enum(data, h, GSK_SESSION_TYPE, GSK_CLIENT_SESSION, FALSE); - if(c == CURLE_OK && appid) - c = set_buffer(data, h, GSK_OS400_APPLICATION_ID, appid, FALSE); - if(c == CURLE_OK && file) - c = set_buffer(data, h, GSK_KEYRING_FILE, file, FALSE); - if(c == CURLE_OK && label) - c = set_buffer(data, h, GSK_KEYRING_LABEL, label, FALSE); - if(c == CURLE_OK && password) - c = set_buffer(data, h, GSK_KEYRING_PW, password, FALSE); - - if(c == CURLE_OK) { + result = set_enum(data, h, GSK_SESSION_TYPE, GSK_CLIENT_SESSION, FALSE); + if(!result && appid) + result = set_buffer(data, h, GSK_OS400_APPLICATION_ID, appid, FALSE); + if(!result && file) + result = set_buffer(data, h, GSK_KEYRING_FILE, file, FALSE); + if(!result && label) + result = set_buffer(data, h, GSK_KEYRING_LABEL, label, FALSE); + if(!result && password) + result = set_buffer(data, h, GSK_KEYRING_PW, password, FALSE); + + if(!result) { /* Locate CAs, Client certificate and key according to our settings. Note: this call may be blocking for some tenths of seconds. */ - c = gskit_status(data, gsk_environment_init(h), - "gsk_environment_init()", CURLE_SSL_CERTPROBLEM); - if(c == CURLE_OK) { + result = gskit_status(data, gsk_environment_init(h), + "gsk_environment_init()", CURLE_SSL_CERTPROBLEM); + if(!result) { *envir = h; - return c; + return result; } } /* Error: rollback. */ gsk_environment_close(&h); - return c; + return result; } @@ -558,7 +558,7 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex) struct SessionHandle *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; gsk_handle envir; - CURLcode cc; + CURLcode result; int rc; char *keyringfile; char *keyringpwd; @@ -600,22 +600,22 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex) if(!envir) { /* Use keyring mode. */ - cc = init_environment(data, &envir, (const char *) NULL, - keyringfile, keyringlabel, keyringpwd); - if(cc != CURLE_OK) - return cc; + result = init_environment(data, &envir, (const char *) NULL, + keyringfile, keyringlabel, keyringpwd); + if(result) + return result; } /* Create secure session. */ - cc = gskit_status(data, gsk_secure_soc_open(envir, &connssl->handle), - "gsk_secure_soc_open()", CURLE_SSL_CONNECT_ERROR); + result = gskit_status(data, gsk_secure_soc_open(envir, &connssl->handle), + "gsk_secure_soc_open()", CURLE_SSL_CONNECT_ERROR); gsk_environment_close(&envir); - if(cc != CURLE_OK) - return cc; + if(result) + return result; /* Determine which SSL/TLS version should be enabled. */ - protoflags = CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK | - CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK; + protoflags = CURL_GSKPROTO_TLSV10_MASK | CURL_GSKPROTO_TLSV11_MASK | + CURL_GSKPROTO_TLSV12_MASK; sni = conn->host.name; switch (data->set.ssl.version) { case CURL_SSLVERSION_SSLv2: @@ -623,7 +623,7 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex) sni = (char *) NULL; break; case CURL_SSLVERSION_SSLv3: - protoflags = CURL_GSKPROTO_SSLV2_MASK; + protoflags = CURL_GSKPROTO_SSLV3_MASK; sni = (char *) NULL; break; case CURL_SSLVERSION_TLSv1: @@ -643,81 +643,84 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex) /* Process SNI. Ignore if not supported (on OS400 < V7R1). */ if(sni) { - cc = set_buffer(data, connssl->handle, - GSK_SSL_EXTN_SERVERNAME_REQUEST, sni, TRUE); - if(cc == CURLE_UNSUPPORTED_PROTOCOL) - cc = CURLE_OK; + result = set_buffer(data, connssl->handle, + GSK_SSL_EXTN_SERVERNAME_REQUEST, sni, TRUE); + if(result == CURLE_UNSUPPORTED_PROTOCOL) + result = CURLE_OK; } /* Set session parameters. */ - if(cc == CURLE_OK) { + if(!result) { /* Compute the handshake timeout. Since GSKit granularity is 1 second, we round up the required value. */ timeout = Curl_timeleft(data, NULL, TRUE); if(timeout < 0) - cc = CURLE_OPERATION_TIMEDOUT; + result = CURLE_OPERATION_TIMEDOUT; else - cc = set_numeric(data, connssl->handle, GSK_HANDSHAKE_TIMEOUT, - (timeout + 999) / 1000); + result = set_numeric(data, connssl->handle, GSK_HANDSHAKE_TIMEOUT, + (timeout + 999) / 1000); } - if(cc == CURLE_OK) - cc = set_numeric(data, connssl->handle, GSK_FD, conn->sock[sockindex]); - if(cc == CURLE_OK) - cc = set_ciphers(data, connssl->handle, &protoflags); + if(!result) + result = set_numeric(data, connssl->handle, GSK_FD, conn->sock[sockindex]); + if(!result) + result = set_ciphers(data, connssl->handle, &protoflags); if(!protoflags) { failf(data, "No SSL protocol/cipher combination enabled"); - cc = CURLE_SSL_CIPHER; + result = CURLE_SSL_CIPHER; } - if(cc == CURLE_OK) - cc = set_enum(data, connssl->handle, GSK_PROTOCOL_SSLV2, - (protoflags & CURL_GSKPROTO_SSLV2_MASK)? - GSK_PROTOCOL_SSLV2_ON: GSK_PROTOCOL_SSLV2_OFF, FALSE); - if(cc == CURLE_OK) - cc = set_enum(data, connssl->handle, GSK_PROTOCOL_SSLV3, - (protoflags & CURL_GSKPROTO_SSLV3_MASK)? - GSK_PROTOCOL_SSLV3_ON: GSK_PROTOCOL_SSLV3_OFF, FALSE); - if(cc == CURLE_OK) - cc = set_enum(data, connssl->handle, GSK_PROTOCOL_TLSV1, - (protoflags & CURL_GSKPROTO_TLSV10_MASK)? - GSK_PROTOCOL_TLSV1_ON: GSK_PROTOCOL_TLSV1_OFF, FALSE); - if(cc == CURLE_OK) { - cc = set_enum(data, connssl->handle, GSK_PROTOCOL_TLSV11, - (protoflags & CURL_GSKPROTO_TLSV11_MASK)? - GSK_TRUE: GSK_FALSE, TRUE); - if(cc == CURLE_UNSUPPORTED_PROTOCOL) { - cc = CURLE_OK; + if(!result) + result = set_enum(data, connssl->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, + (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, + (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, + (protoflags & CURL_GSKPROTO_TLSV11_MASK)? + GSK_TRUE: GSK_FALSE, TRUE); + if(result == CURLE_UNSUPPORTED_PROTOCOL) { + result = CURLE_OK; if(protoflags == CURL_GSKPROTO_TLSV11_MASK) { failf(data, "TLS 1.1 not yet supported"); - cc = CURLE_SSL_CIPHER; + result = CURLE_SSL_CIPHER; } } } - if(cc == CURLE_OK) { - cc = set_enum(data, connssl->handle, GSK_PROTOCOL_TLSV12, - (protoflags & CURL_GSKPROTO_TLSV12_MASK)? - GSK_TRUE: GSK_FALSE, TRUE); - if(cc == CURLE_UNSUPPORTED_PROTOCOL) { - cc = CURLE_OK; + if(!result) { + result = set_enum(data, connssl->handle, GSK_PROTOCOL_TLSV12, + (protoflags & CURL_GSKPROTO_TLSV12_MASK)? + GSK_TRUE: GSK_FALSE, TRUE); + if(result == CURLE_UNSUPPORTED_PROTOCOL) { + result = CURLE_OK; if(protoflags == CURL_GSKPROTO_TLSV12_MASK) { failf(data, "TLS 1.2 not yet supported"); - cc = CURLE_SSL_CIPHER; + result = CURLE_SSL_CIPHER; } } } - if(cc == CURLE_OK) - cc = set_enum(data, connssl->handle, GSK_SERVER_AUTH_TYPE, - data->set.ssl.verifypeer? GSK_SERVER_AUTH_FULL: - GSK_SERVER_AUTH_PASSTHRU, FALSE); + if(!result) + result = set_enum(data, connssl->handle, GSK_SERVER_AUTH_TYPE, + data->set.ssl.verifypeer? GSK_SERVER_AUTH_FULL: + GSK_SERVER_AUTH_PASSTHRU, FALSE); - if(cc == CURLE_OK) { + if(!result) { /* Start handshake. Try asynchronous first. */ memset(&commarea, 0, sizeof commarea); connssl->iocport = QsoCreateIOCompletionPort(); if(connssl->iocport != -1) { - cc = gskit_status(data, gsk_secure_soc_startInit(connssl->handle, - connssl->iocport, &commarea), - "gsk_secure_soc_startInit()", CURLE_SSL_CONNECT_ERROR); - if(cc == CURLE_OK) { + result = gskit_status(data, + gsk_secure_soc_startInit(connssl->handle, + connssl->iocport, + &commarea), + "gsk_secure_soc_startInit()", + CURLE_SSL_CONNECT_ERROR); + if(!result) { connssl->connecting_state = ssl_connect_2; return CURLE_OK; } @@ -725,12 +728,13 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex) close_async_handshake(connssl); } else if(errno != ENOBUFS) - cc = gskit_status(data, GSK_ERROR_IO, "QsoCreateIOCompletionPort()", 0); + result = gskit_status(data, GSK_ERROR_IO, + "QsoCreateIOCompletionPort()", 0); else { /* No more completion port available. Use synchronous IO. */ - cc = gskit_status(data, gsk_secure_soc_init(connssl->handle), - "gsk_secure_soc_init()", CURLE_SSL_CONNECT_ERROR); - if(cc == CURLE_OK) { + result = gskit_status(data, gsk_secure_soc_init(connssl->handle), + "gsk_secure_soc_init()", CURLE_SSL_CONNECT_ERROR); + if(!result) { connssl->connecting_state = ssl_connect_3; return CURLE_OK; } @@ -739,7 +743,7 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex) /* Error: rollback. */ close_one(connssl, data); - return cc; + return result; } @@ -751,7 +755,7 @@ static CURLcode gskit_connect_step2(struct connectdata *conn, int sockindex, Qso_OverlappedIO_t cstat; long timeout_ms; struct timeval stmv; - CURLcode cc; + CURLcode result; /* Poll or wait for end of SSL asynchronous handshake. */ @@ -786,12 +790,12 @@ static CURLcode gskit_connect_step2(struct connectdata *conn, int sockindex, } break; } - cc = gskit_status(data, cstat.returnValue, "SSL handshake", - CURLE_SSL_CONNECT_ERROR); - if(cc == CURLE_OK) + result = gskit_status(data, cstat.returnValue, "SSL handshake", + CURLE_SSL_CONNECT_ERROR); + if(!result) connssl->connecting_state = ssl_connect_3; close_async_handshake(connssl); - return cc; + return result; } @@ -804,8 +808,9 @@ static CURLcode gskit_connect_step3(struct connectdata *conn, int sockindex) const gsk_cert_data_elem *p; const char *cert = (const char *) NULL; const char *certend; + const char *ptr; int i; - CURLcode cc; + CURLcode result; /* SSL handshake done: gather certificate info and verify host. */ @@ -838,9 +843,9 @@ static CURLcode gskit_connect_step3(struct connectdata *conn, int sockindex) } /* Verify host. */ - cc = Curl_verifyhost(conn, cert, certend); - if(cc != CURLE_OK) - return cc; + result = Curl_verifyhost(conn, cert, certend); + if(result) + return result; /* The only place GSKit can get the whole CA chain is a validation callback where no user data pointer is available. Therefore it's not @@ -848,12 +853,31 @@ static CURLcode gskit_connect_step3(struct connectdata *conn, int sockindex) However the server certificate may be available, thus we can return info about it. */ if(data->set.ssl.certinfo) { - if(Curl_ssl_init_certinfo(data, 1)) - return CURLE_OUT_OF_MEMORY; + result = Curl_ssl_init_certinfo(data, 1); + if(result) + return result; + if(cert) { - cc = Curl_extract_certinfo(conn, 0, cert, certend); - if(cc != CURLE_OK) - return cc; + result = Curl_extract_certinfo(conn, 0, cert, certend); + if(result) + return result; + } + } + + /* Check pinned public key. */ + ptr = data->set.str[STRING_SSL_PINNEDPUBLICKEY]; + if(!result && ptr) { + curl_X509certificate x509; + curl_asn1Element *p; + + if(!cert) + return CURLE_SSL_PINNEDPUBKEYNOTMATCH; + Curl_parseX509(&x509, cert, certend); + p = &x509.subjectPublicKeyInfo; + result = Curl_pin_peer_pubkey(ptr, p->header, p->end - p->header); + if(result) { + failf(data, "SSL: public key does not match pinned public key!"); + return result; } } @@ -869,7 +893,7 @@ static CURLcode gskit_connect_common(struct connectdata *conn, int sockindex, struct ssl_connect_data *connssl = &conn->ssl[sockindex]; long timeout_ms; Qso_OverlappedIO_t cstat; - CURLcode cc = CURLE_OK; + CURLcode result = CURLE_OK; *done = connssl->state == ssl_connection_complete; if(*done) @@ -883,31 +907,31 @@ static CURLcode gskit_connect_common(struct connectdata *conn, int sockindex, if(timeout_ms < 0) { /* no need to continue if time already is up */ failf(data, "SSL connection timeout"); - cc = CURLE_OPERATION_TIMEDOUT; + result = CURLE_OPERATION_TIMEDOUT; } else - cc = gskit_connect_step1(conn, sockindex); + result = gskit_connect_step1(conn, sockindex); } /* Step 2: check if handshake is over. */ - if(cc == CURLE_OK && connssl->connecting_state == ssl_connect_2) { + if(!result && connssl->connecting_state == ssl_connect_2) { /* check allowed time left */ timeout_ms = Curl_timeleft(data, NULL, TRUE); if(timeout_ms < 0) { /* no need to continue if time already is up */ failf(data, "SSL connection timeout"); - cc = CURLE_OPERATION_TIMEDOUT; + result = CURLE_OPERATION_TIMEDOUT; } else - cc = gskit_connect_step2(conn, sockindex, nonblocking); + result = gskit_connect_step2(conn, sockindex, nonblocking); } /* Step 3: gather certificate info, verify host. */ - if(cc == CURLE_OK && connssl->connecting_state == ssl_connect_3) - cc = gskit_connect_step3(conn, sockindex); + if(!result && connssl->connecting_state == ssl_connect_3) + result = gskit_connect_step3(conn, sockindex); - if(cc != CURLE_OK) + if(result) close_one(connssl, data); else if(connssl->connecting_state == ssl_connect_done) { connssl->state = ssl_connection_complete; @@ -917,7 +941,7 @@ static CURLcode gskit_connect_common(struct connectdata *conn, int sockindex, *done = TRUE; } - return cc; + return result; } @@ -925,24 +949,24 @@ CURLcode Curl_gskit_connect_nonblocking(struct connectdata *conn, int sockindex, bool *done) { - CURLcode cc; + CURLcode result; - cc = gskit_connect_common(conn, sockindex, TRUE, done); - if(*done || cc != CURLE_OK) + result = gskit_connect_common(conn, sockindex, TRUE, done); + if(*done || result) conn->ssl[sockindex].connecting_state = ssl_connect_1; - return cc; + return result; } CURLcode Curl_gskit_connect(struct connectdata *conn, int sockindex) { - CURLcode retcode; + CURLcode result; bool done; conn->ssl[sockindex].connecting_state = ssl_connect_1; - retcode = gskit_connect_common(conn, sockindex, FALSE, &done); - if(retcode) - return retcode; + result = gskit_connect_common(conn, sockindex, FALSE, &done); + if(result) + return result; DEBUGASSERT(done); @@ -960,14 +984,6 @@ void Curl_gskit_close(struct connectdata *conn, int sockindex) } -int Curl_gskit_close_all(struct SessionHandle *data) -{ - /* Unimplemented. */ - (void) data; - return 0; -} - - int Curl_gskit_shutdown(struct connectdata *conn, int sockindex) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; diff --git a/Utilities/cmcurl/lib/vtls/gskit.h b/Utilities/cmcurl/lib/vtls/gskit.h index a4caa6f..af31faf 100644 --- a/Utilities/cmcurl/lib/vtls/gskit.h +++ b/Utilities/cmcurl/lib/vtls/gskit.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -32,15 +32,20 @@ #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); +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_close_all(struct SessionHandle * data); -int Curl_gskit_shutdown(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); +size_t Curl_gskit_version(char *buffer, size_t size); +int Curl_gskit_check_cxn(struct connectdata *cxn); + +/* 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 @@ -50,7 +55,7 @@ int Curl_gskit_check_cxn(struct connectdata * cxn); /* No session handling for GSKit */ #define curlssl_session_free(x) Curl_nop_stmt -#define curlssl_close_all Curl_gskit_close_all +#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 @@ -59,7 +64,8 @@ int Curl_gskit_check_cxn(struct connectdata * cxn); #define curlssl_version Curl_gskit_version #define curlssl_check_cxn(x) Curl_gskit_check_cxn(x) #define curlssl_data_pending(x,y) 0 -#define CURL_SSL_BACKEND CURLSSLBACKEND_GSKIT +#define curlssl_random(x,y,z) -1 + #endif /* USE_GSKIT */ #endif /* HEADER_CURL_GSKIT_H */ diff --git a/Utilities/cmcurl/lib/vtls/gtls.c b/Utilities/cmcurl/lib/vtls/gtls.c index d64f95d..c54dfc1 100644 --- a/Utilities/cmcurl/lib/vtls/gtls.c +++ b/Utilities/cmcurl/lib/vtls/gtls.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -32,12 +32,14 @@ #ifdef USE_GNUTLS +#include <gnutls/abstract.h> #include <gnutls/gnutls.h> #include <gnutls/x509.h> #ifdef USE_GNUTLS_NETTLE #include <gnutls/crypto.h> #include <nettle/md5.h> +#include <nettle/sha2.h> #else #include <gcrypt.h> #endif @@ -52,9 +54,8 @@ #include "select.h" #include "rawstr.h" #include "warnless.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> +#include "x509asn1.h" +#include "curl_printf.h" #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" @@ -91,14 +92,23 @@ static bool gtls_inited = FALSE; # define GNUTLS_MAPS_WINSOCK_ERRORS 1 # endif -# ifdef USE_NGHTTP2 -# undef HAS_ALPN -# if (GNUTLS_VERSION_NUMBER >= 0x030200) -# define HAS_ALPN -# endif +# if (GNUTLS_VERSION_NUMBER >= 0x030200) +# define HAS_ALPN +# endif + +# if (GNUTLS_VERSION_NUMBER >= 0x03020d) +# define HAS_OCSP +# endif + +# if (GNUTLS_VERSION_NUMBER >= 0x030306) +# define HAS_CAPATH # endif #endif +#ifdef HAS_OCSP +# include <gnutls/ocsp.h> +#endif + /* * 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() @@ -203,7 +213,7 @@ static void showtime(struct SessionHandle *data, snprintf(data->state.buffer, BUFSIZE, - "\t %s: %s, %02d %s %4d %02d:%02d:%02d GMT\n", + "\t %s: %s, %02d %s %4d %02d:%02d:%02d GMT", text, Curl_wkday[tm->tm_wday?tm->tm_wday-1:6], tm->tm_mday, @@ -222,7 +232,7 @@ static gnutls_datum_t load_file (const char *file) long filelen; void *ptr; - if(!(f = fopen(file, "r"))) + if(!(f = fopen(file, "rb"))) return loaded_file; if(fseek(f, 0, SEEK_END) != 0 || (filelen = ftell(f)) < 0 @@ -306,8 +316,6 @@ static CURLcode handshake(struct connectdata *conn, gnutls_record_get_direction(session)? ssl_connect_2_writing:ssl_connect_2_reading; continue; - if(nonblocking) - return CURLE_OK; } else if((rc < 0) && !gnutls_error_is_fatal(rc)) { const char *strerr = NULL; @@ -320,7 +328,8 @@ static CURLcode handshake(struct connectdata *conn, if(strerr == NULL) strerr = gnutls_strerror(rc); - failf(data, "gnutls_handshake() warning: %s", strerr); + infof(data, "gnutls_handshake() warning: %s\n", strerr); + continue; } else if(rc < 0) { const char *strerr = NULL; @@ -393,10 +402,6 @@ gtls_connect_step1(struct connectdata *conn, const char* prioritylist; const char *err = NULL; #endif -#ifdef HAS_ALPN - int protocols_size = 2; - gnutls_datum_t protocols[2]; -#endif if(conn->ssl[sockindex].state == ssl_connection_complete) /* to make us tolerant against being called more than once for the @@ -464,6 +469,24 @@ gtls_connect_step1(struct connectdata *conn, rc, data->set.ssl.CAfile); } +#ifdef HAS_CAPATH + if(data->set.ssl.CApath) { + /* set the trusted CA cert directory */ + rc = gnutls_certificate_set_x509_trust_dir(conn->ssl[sockindex].cred, + data->set.ssl.CApath, + GNUTLS_X509_FMT_PEM); + if(rc < 0) { + infof(data, "error reading ca cert file %s (%s)\n", + data->set.ssl.CAfile, gnutls_strerror(rc)); + if(data->set.ssl.verifypeer) + return CURLE_SSL_CACERT_BADFILE; + } + else + infof(data, "found %d certificates in %s\n", + rc, data->set.ssl.CApath); + } +#endif + if(data->set.ssl.CRLfile) { /* set the CRL list file */ rc = gnutls_certificate_set_x509_crl_file(conn->ssl[sockindex].cred, @@ -610,19 +633,25 @@ gtls_connect_step1(struct connectdata *conn, #endif #ifdef HAS_ALPN - if(data->set.httpversion == CURL_HTTP_VERSION_2_0) { - if(data->set.ssl_enable_alpn) { - protocols[0].data = NGHTTP2_PROTO_VERSION_ID; - protocols[0].size = NGHTTP2_PROTO_VERSION_ID_LEN; - protocols[1].data = ALPN_HTTP_1_1; - protocols[1].size = ALPN_HTTP_1_1_LENGTH; - gnutls_alpn_set_protocols(session, protocols, protocols_size, 0); - infof(data, "ALPN, offering %s, %s\n", NGHTTP2_PROTO_VERSION_ID, - ALPN_HTTP_1_1); - } - else { - infof(data, "SSL, can't negotiate HTTP/2.0 without ALPN\n"); + if(data->set.ssl_enable_alpn) { + int cur = 0; + gnutls_datum_t protocols[2]; + +#ifdef USE_NGHTTP2 + if(data->set.httpversion == CURL_HTTP_VERSION_2_0) { + protocols[cur].data = (unsigned char *)NGHTTP2_PROTO_VERSION_ID; + protocols[cur].size = NGHTTP2_PROTO_VERSION_ID_LEN; + cur++; + infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID); } +#endif + + protocols[cur].data = (unsigned char *)ALPN_HTTP_1_1; + protocols[cur].size = ALPN_HTTP_1_1_LENGTH; + cur++; + infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1); + + gnutls_alpn_set_protocols(session, protocols, cur, 0); } #endif @@ -644,13 +673,21 @@ gtls_connect_step1(struct connectdata *conn, if(data->set.ssl.authtype == CURL_TLSAUTH_SRP) { rc = gnutls_credentials_set(session, GNUTLS_CRD_SRP, conn->ssl[sockindex].srp_client_cred); - if(rc != GNUTLS_E_SUCCESS) + if(rc != GNUTLS_E_SUCCESS) { failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc)); + return CURLE_SSL_CONNECT_ERROR; + } } else #endif + { rc = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, conn->ssl[sockindex].cred); + if(rc != GNUTLS_E_SUCCESS) { + failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc)); + return CURLE_SSL_CONNECT_ERROR; + } + } /* set the connection handle (file descriptor for the socket) */ gnutls_transport_set_ptr(session, @@ -663,6 +700,16 @@ gtls_connect_step1(struct connectdata *conn, /* lowat must be set to zero when using custom push and pull functions. */ gnutls_transport_set_lowat(session, 0); +#ifdef HAS_OCSP + if(data->set.ssl.verifystatus) { + rc = gnutls_ocsp_status_request_enable_client(session, NULL, 0, NULL); + if(rc != GNUTLS_E_SUCCESS) { + failf(data, "gnutls_ocsp_status_request_enable_client() failed: %d", rc); + return CURLE_SSL_CONNECT_ERROR; + } + } +#endif + /* This might be a reconnect, so we check for a session ID in the cache to speed up things */ @@ -677,6 +724,62 @@ gtls_connect_step1(struct connectdata *conn, return CURLE_OK; } +static CURLcode pkp_pin_peer_pubkey(gnutls_x509_crt_t cert, + const char *pinnedpubkey) +{ + /* Scratch */ + size_t len1 = 0, len2 = 0; + unsigned char *buff1 = NULL; + + gnutls_pubkey_t key = NULL; + + /* Result is returned to caller */ + int ret = 0; + CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH; + + /* if a path wasn't specified, don't pin */ + if(NULL == pinnedpubkey) + return CURLE_OK; + + if(NULL == cert) + return result; + + do { + /* Begin Gyrations to get the public key */ + gnutls_pubkey_init(&key); + + ret = gnutls_pubkey_import_x509(key, cert, 0); + if(ret < 0) + break; /* failed */ + + ret = gnutls_pubkey_export(key, GNUTLS_X509_FMT_DER, NULL, &len1); + if(ret != GNUTLS_E_SHORT_MEMORY_BUFFER || len1 == 0) + break; /* failed */ + + buff1 = malloc(len1); + if(NULL == buff1) + break; /* failed */ + + len2 = len1; + + ret = gnutls_pubkey_export(key, GNUTLS_X509_FMT_DER, buff1, &len2); + if(ret < 0 || len1 != len2) + break; /* failed */ + + /* End Gyrations */ + + /* The one good exit point */ + result = Curl_pin_peer_pubkey(pinnedpubkey, buff1, len1); + } while(0); + + if(NULL != key) + gnutls_pubkey_deinit(key); + + Curl_safefree(buff1); + + return result; +} + static Curl_recv gtls_recv; static Curl_send gtls_send; @@ -686,8 +789,8 @@ gtls_connect_step3(struct connectdata *conn, { unsigned int cert_list_size; const gnutls_datum_t *chainp; - unsigned int verify_status; - gnutls_x509_crt_t x509_cert,x509_issuer; + unsigned int verify_status = 0; + gnutls_x509_crt_t x509_cert, x509_issuer; gnutls_datum_t issuerp; char certbuf[256] = ""; /* big enough? */ size_t size; @@ -698,13 +801,23 @@ gtls_connect_step3(struct connectdata *conn, struct SessionHandle *data = conn->data; gnutls_session_t session = conn->ssl[sockindex].session; int rc; - int incache; + bool incache; void *ssl_sessionid; #ifdef HAS_ALPN gnutls_datum_t proto; #endif CURLcode result = CURLE_OK; + gnutls_protocol_t version = gnutls_protocol_get_version(session); + + /* the name of the cipher suite used, e.g. ECDHE_RSA_AES_256_GCM_SHA384. */ + ptr = gnutls_cipher_suite_get_name(gnutls_kx_get(session), + gnutls_cipher_get(session), + gnutls_mac_get(session)); + + infof(data, "SSL connection using %s / %s\n", + gnutls_protocol_get_name(version), ptr); + /* This function will return the peer's raw certificate (chain) as sent by the peer. These certificates are in raw format (DER encoded for X.509). In case of a X.509 then a certificate list may be present. The @@ -735,6 +848,23 @@ gtls_connect_step3(struct connectdata *conn, infof(data, "\t common name: WARNING couldn't obtain\n"); } + if(data->set.ssl.certinfo && chainp) { + unsigned int i; + + result = Curl_ssl_init_certinfo(data, cert_list_size); + if(result) + return result; + + for(i = 0; i < cert_list_size; i++) { + const char *beg = (const char *) chainp[i].data; + const char *end = beg + chainp[i].size; + + result = Curl_extract_certinfo(conn, i, beg, end); + if(result) + return result; + } + } + if(data->set.ssl.verifypeer) { /* This function will try to verify the peer's certificate and return its status (trusted, invalid etc.). The value of status should be one or @@ -766,6 +896,111 @@ gtls_connect_step3(struct connectdata *conn, else infof(data, "\t server certificate verification SKIPPED\n"); +#ifdef HAS_OCSP + if(data->set.ssl.verifystatus) { + if(gnutls_ocsp_status_request_is_checked(session, 0) == 0) { + gnutls_datum_t status_request; + gnutls_ocsp_resp_t ocsp_resp; + + gnutls_ocsp_cert_status_t status; + gnutls_x509_crl_reason_t reason; + + rc = gnutls_ocsp_status_request_get(session, &status_request); + + infof(data, "\t server certificate status verification FAILED\n"); + + if(rc == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { + failf(data, "No OCSP response received"); + return CURLE_SSL_INVALIDCERTSTATUS; + } + + if(rc < 0) { + failf(data, "Invalid OCSP response received"); + return CURLE_SSL_INVALIDCERTSTATUS; + } + + gnutls_ocsp_resp_init(&ocsp_resp); + + rc = gnutls_ocsp_resp_import(ocsp_resp, &status_request); + if(rc < 0) { + failf(data, "Invalid OCSP response received"); + return CURLE_SSL_INVALIDCERTSTATUS; + } + + rc = gnutls_ocsp_resp_get_single(ocsp_resp, 0, NULL, NULL, NULL, NULL, + &status, NULL, NULL, NULL, &reason); + + switch(status) { + case GNUTLS_OCSP_CERT_GOOD: + break; + + case GNUTLS_OCSP_CERT_REVOKED: { + const char *crl_reason; + + switch(reason) { + default: + case GNUTLS_X509_CRLREASON_UNSPECIFIED: + crl_reason = "unspecified reason"; + break; + + case GNUTLS_X509_CRLREASON_KEYCOMPROMISE: + crl_reason = "private key compromised"; + break; + + case GNUTLS_X509_CRLREASON_CACOMPROMISE: + crl_reason = "CA compromised"; + break; + + case GNUTLS_X509_CRLREASON_AFFILIATIONCHANGED: + crl_reason = "affiliation has changed"; + break; + + case GNUTLS_X509_CRLREASON_SUPERSEDED: + crl_reason = "certificate superseded"; + break; + + case GNUTLS_X509_CRLREASON_CESSATIONOFOPERATION: + crl_reason = "operation has ceased"; + break; + + case GNUTLS_X509_CRLREASON_CERTIFICATEHOLD: + crl_reason = "certificate is on hold"; + break; + + case GNUTLS_X509_CRLREASON_REMOVEFROMCRL: + crl_reason = "will be removed from delta CRL"; + break; + + case GNUTLS_X509_CRLREASON_PRIVILEGEWITHDRAWN: + crl_reason = "privilege withdrawn"; + break; + + case GNUTLS_X509_CRLREASON_AACOMPROMISE: + crl_reason = "AA compromised"; + break; + } + + failf(data, "Server certificate was revoked: %s", crl_reason); + break; + } + + default: + case GNUTLS_OCSP_CERT_UNKNOWN: + failf(data, "Server certificate status is unknown"); + break; + } + + gnutls_ocsp_resp_deinit(ocsp_resp); + + return CURLE_SSL_INVALIDCERTSTATUS; + } + else + infof(data, "\t server certificate status verification OK\n"); + } + else + infof(data, "\t server certificate status verification SKIPPED\n"); +#endif + /* initialize an X.509 certificate structure. */ gnutls_x509_crt_init(&x509_cert); @@ -778,14 +1013,16 @@ gtls_connect_step3(struct connectdata *conn, gnutls_x509_crt_init(&x509_issuer); issuerp = load_file(data->set.ssl.issuercert); gnutls_x509_crt_import(x509_issuer, &issuerp, GNUTLS_X509_FMT_PEM); - rc = gnutls_x509_crt_check_issuer(x509_cert,x509_issuer); + rc = gnutls_x509_crt_check_issuer(x509_cert, x509_issuer); + gnutls_x509_crt_deinit(x509_issuer); unload_file(issuerp); if(rc <= 0) { failf(data, "server certificate issuer check failed (IssuerCert: %s)", data->set.ssl.issuercert?data->set.ssl.issuercert:"none"); + gnutls_x509_crt_deinit(x509_cert); return CURLE_SSL_ISSUER_ERROR; } - infof(data,"\t server certificate issuer check OK (Issuer Cert: %s)\n", + infof(data, "\t server certificate issuer check OK (Issuer Cert: %s)\n", data->set.ssl.issuercert?data->set.ssl.issuercert:"none"); } @@ -868,6 +1105,7 @@ gtls_connect_step3(struct connectdata *conn, if(certclock == (time_t)-1) { if(data->set.ssl.verifypeer) { failf(data, "server cert expiration date verify failed"); + gnutls_x509_crt_deinit(x509_cert); return CURLE_SSL_CONNECT_ERROR; } else @@ -877,6 +1115,7 @@ gtls_connect_step3(struct connectdata *conn, if(certclock < time(NULL)) { if(data->set.ssl.verifypeer) { failf(data, "server certificate expiration date has passed."); + gnutls_x509_crt_deinit(x509_cert); return CURLE_PEER_FAILED_VERIFICATION; } else @@ -891,6 +1130,7 @@ gtls_connect_step3(struct connectdata *conn, if(certclock == (time_t)-1) { if(data->set.ssl.verifypeer) { failf(data, "server cert activation date verify failed"); + gnutls_x509_crt_deinit(x509_cert); return CURLE_SSL_CONNECT_ERROR; } else @@ -900,6 +1140,7 @@ gtls_connect_step3(struct connectdata *conn, if(certclock > time(NULL)) { if(data->set.ssl.verifypeer) { failf(data, "server certificate not activated yet."); + gnutls_x509_crt_deinit(x509_cert); return CURLE_PEER_FAILED_VERIFICATION; } else @@ -909,9 +1150,18 @@ gtls_connect_step3(struct connectdata *conn, infof(data, "\t server certificate activation date OK\n"); } + ptr = data->set.str[STRING_SSL_PINNEDPUBLICKEY]; + if(ptr) { + result = pkp_pin_peer_pubkey(x509_cert, ptr); + if(result != CURLE_OK) { + failf(data, "SSL: public key does not match pinned public key!"); + gnutls_x509_crt_deinit(x509_cert); + return result; + } + } + /* Show: - - ciphers used - subject - start date - expire date @@ -951,14 +1201,6 @@ gtls_connect_step3(struct connectdata *conn, /* the *_get_name() says "NULL" if GNUTLS_COMP_NULL is returned */ infof(data, "\t compression: %s\n", ptr); - /* the name of the cipher used. ie 3DES. */ - ptr = gnutls_cipher_get_name(gnutls_cipher_get(session)); - infof(data, "\t cipher: %s\n", ptr); - - /* the MAC algorithms name. ie SHA1 */ - ptr = gnutls_mac_get_name(gnutls_mac_get(session)); - infof(data, "\t MAC: %s\n", ptr); - #ifdef HAS_ALPN if(data->set.ssl_enable_alpn) { rc = gnutls_alpn_get_selected_protocol(session, &proto); @@ -966,19 +1208,21 @@ gtls_connect_step3(struct connectdata *conn, infof(data, "ALPN, server accepted to use %.*s\n", proto.size, proto.data); +#ifdef USE_NGHTTP2 if(proto.size == NGHTTP2_PROTO_VERSION_ID_LEN && - memcmp(NGHTTP2_PROTO_VERSION_ID, proto.data, - NGHTTP2_PROTO_VERSION_ID_LEN) == 0) { - conn->negnpn = NPN_HTTP2; + !memcmp(NGHTTP2_PROTO_VERSION_ID, proto.data, + NGHTTP2_PROTO_VERSION_ID_LEN)) { + conn->negnpn = CURL_HTTP_VERSION_2_0; } - else if(proto.size == ALPN_HTTP_1_1_LENGTH && memcmp(ALPN_HTTP_1_1, - proto.data, ALPN_HTTP_1_1_LENGTH) == 0) { - conn->negnpn = NPN_HTTP1_1; + else +#endif + if(proto.size == ALPN_HTTP_1_1_LENGTH && + !memcmp(ALPN_HTTP_1_1, proto.data, ALPN_HTTP_1_1_LENGTH)) { + conn->negnpn = CURL_HTTP_VERSION_1_1; } } - else { + else infof(data, "ALPN, server did not agree to a protocol\n"); - } } #endif @@ -1079,12 +1323,12 @@ Curl_gtls_connect(struct connectdata *conn, int sockindex) { - CURLcode retcode; + CURLcode result; bool done = FALSE; - retcode = gtls_connect_common(conn, sockindex, FALSE, &done); - if(retcode) - return retcode; + result = gtls_connect_common(conn, sockindex, FALSE, &done); + if(result) + return result; DEBUGASSERT(done); @@ -1110,12 +1354,6 @@ static ssize_t gtls_send(struct connectdata *conn, return rc; } -void Curl_gtls_close_all(struct SessionHandle *data) -{ - /* FIX: make the OpenSSL code more generic and use parts of it here */ - (void)data; -} - static void close_one(struct connectdata *conn, int idx) { @@ -1232,10 +1470,10 @@ static ssize_t gtls_recv(struct connectdata *conn, /* connection data */ if(ret == GNUTLS_E_REHANDSHAKE) { /* BLOCKING call, this is bad but a work-around for now. Fixing this "the proper way" takes a whole lot of work. */ - CURLcode rc = handshake(conn, num, FALSE, FALSE); - if(rc) + CURLcode result = handshake(conn, num, FALSE, FALSE); + if(result) /* handshake() writes error message on its own */ - *curlcode = rc; + *curlcode = result; else *curlcode = CURLE_AGAIN; /* then return as if this was a wouldblock */ return -1; @@ -1320,4 +1558,32 @@ void Curl_gtls_md5sum(unsigned char *tmp, /* input */ #endif } +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; + sha256_init(&SHA256pw); + sha256_update(&SHA256pw, (unsigned int)tmplen, tmp); + sha256_digest(&SHA256pw, (unsigned int)sha256len, sha256sum); +#elif defined(USE_GNUTLS) + gcry_md_hd_t SHA256pw; + gcry_md_open(&SHA256pw, GCRY_MD_SHA256, 0); + gcry_md_write(SHA256pw, tmp, tmplen); + memcpy(sha256sum, gcry_md_read (SHA256pw, 0), sha256len); + gcry_md_close(SHA256pw); +#endif +} + +bool Curl_gtls_cert_status_request(void) +{ +#ifdef HAS_OCSP + return TRUE; +#else + return FALSE; +#endif +} + #endif /* USE_GNUTLS */ diff --git a/Utilities/cmcurl/lib/vtls/gtls.h b/Utilities/cmcurl/lib/vtls/gtls.h index cd6152c..0afd9b9 100644 --- a/Utilities/cmcurl/lib/vtls/gtls.h +++ b/Utilities/cmcurl/lib/vtls/gtls.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -35,10 +35,6 @@ CURLcode Curl_gtls_connect_nonblocking(struct connectdata *conn, int sockindex, bool *done); -/* tell GnuTLS to close down all open information regarding connections (and - thus session ID caching etc) */ -void Curl_gtls_close_all(struct SessionHandle *data); - /* close a SSL connection */ void Curl_gtls_close(struct connectdata *conn, int sockindex); @@ -52,9 +48,21 @@ 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); -/* this backend provides these functions: */ -#define have_curlssl_md5sum 1 +bool Curl_gtls_cert_status_request(void); + +/* 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 /* API setup for GnuTLS */ #define curlssl_init Curl_gtls_init @@ -62,18 +70,19 @@ void Curl_gtls_md5sum(unsigned char *tmp, /* input */ #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 Curl_gtls_close_all +#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) (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_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) (x=x, -1) -#define curlssl_data_pending(x,y) (x=x, y=y, 0) +#define curlssl_check_cxn(x) ((void)x, -1) +#define curlssl_data_pending(x,y) ((void)x, (void)y, 0) #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 CURL_SSL_BACKEND CURLSSLBACKEND_GNUTLS +#define curlssl_sha256sum(a,b,c,d) Curl_gtls_sha256sum(a,b,c,d) +#define curlssl_cert_status_request() Curl_gtls_cert_status_request() #endif /* USE_GNUTLS */ #endif /* HEADER_CURL_GTLS_H */ diff --git a/Utilities/cmcurl/lib/vtls/nss.c b/Utilities/cmcurl/lib/vtls/nss.c index 83b3e32..91727c7 100644 --- a/Utilities/cmcurl/lib/vtls/nss.c +++ b/Utilities/cmcurl/lib/vtls/nss.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -38,10 +38,7 @@ #include "select.h" #include "vtls.h" #include "llist.h" - -#define _MPRINTF_REPLACE /* use the internal *printf() functions */ -#include <curl/mprintf.h> - +#include "curl_printf.h" #include "nssg.h" #include <nspr.h> #include <nss.h> @@ -59,13 +56,20 @@ #include <base64.h> #include <cert.h> #include <prerror.h> +#include <keyhi.h> /* for SECKEY_DestroyPublicKey() */ + +#define NSSVERNUM ((NSS_VMAJOR<<16)|(NSS_VMINOR<<8)|NSS_VPATCH) + +#if NSSVERNUM >= 0x030f00 /* 3.15.0 */ +#include <ocsp.h> +#endif -#include "curl_memory.h" #include "rawstr.h" #include "warnless.h" #include "x509asn1.h" -/* The last #include file should be: */ +/* The last #include files should be: */ +#include "curl_memory.h" #include "memdebug.h" #define SSL_DIR "/etc/pki/nssdb" @@ -343,7 +347,7 @@ static CURLcode nss_create_object(struct ssl_connect_data *ssl, CK_BBOOL ckfalse = CK_FALSE; CK_ATTRIBUTE attrs[/* max count of attributes */ 4]; int attr_cnt = 0; - CURLcode err = (cacert) + CURLcode result = (cacert) ? CURLE_SSL_CACERT_BADFILE : CURLE_SSL_CERTPROBLEM; @@ -355,7 +359,7 @@ static CURLcode nss_create_object(struct ssl_connect_data *ssl, slot = PK11_FindSlotByName(slot_name); free(slot_name); if(!slot) - return err; + return result; PK11_SETATTRS(attrs, attr_cnt, CKA_CLASS, &obj_class, sizeof(obj_class)); PK11_SETATTRS(attrs, attr_cnt, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL)); @@ -370,7 +374,7 @@ static CURLcode nss_create_object(struct ssl_connect_data *ssl, obj = PK11_CreateGenericObject(slot, attrs, attr_cnt, PR_FALSE); PK11_FreeSlot(slot); if(!obj) - return err; + return result; if(!Curl_llist_insert_next(ssl->obj_list, ssl->obj_list->tail, obj)) { PK11_DestroyGenericObject(obj); @@ -405,16 +409,16 @@ static void nss_destroy_crl_item(void *user, void *ptr) static CURLcode nss_load_cert(struct ssl_connect_data *ssl, const char *filename, PRBool cacert) { - CURLcode err = (cacert) + CURLcode result = (cacert) ? CURLE_SSL_CACERT_BADFILE : CURLE_SSL_CERTPROBLEM; /* libnsspem.so leaks memory if the requested file does not exist. For more * details, go to <https://bugzilla.redhat.com/734760>. */ if(is_file(filename)) - err = nss_create_object(ssl, CKO_CERTIFICATE, filename, cacert); + result = nss_create_object(ssl, CKO_CERTIFICATE, filename, cacert); - if(CURLE_OK == err && !cacert) { + if(!result && !cacert) { /* we have successfully loaded a client certificate */ CERTCertificate *cert; char *nickname = NULL; @@ -436,7 +440,7 @@ static CURLcode nss_load_cert(struct ssl_connect_data *ssl, } } - return err; + return result; } /* add given CRL to cache if it is not already there */ @@ -448,7 +452,7 @@ static CURLcode nss_cache_crl(SECItem *crl_der) /* CRL already cached */ SEC_DestroyCrl(crl); SECITEM_FreeItem(crl_der, PR_TRUE); - return CURLE_SSL_CRL_BADFILE; + return CURLE_OK; } /* acquire lock before call of CERT_CacheCRL() and accessing nss_crl_list */ @@ -542,14 +546,15 @@ static CURLcode nss_load_key(struct connectdata *conn, int sockindex, { PK11SlotInfo *slot; SECStatus status; - CURLcode rv; + CURLcode result; struct ssl_connect_data *ssl = conn->ssl; + (void)sockindex; /* unused */ - rv = nss_create_object(ssl, CKO_PRIVATE_KEY, key_file, FALSE); - if(CURLE_OK != rv) { + result = nss_create_object(ssl, CKO_PRIVATE_KEY, key_file, FALSE); + if(result) { PR_SetError(SEC_ERROR_BAD_KEY, 0); - return rv; + return result; } slot = PK11_FindSlotByName("PEM Token #1"); @@ -563,9 +568,8 @@ static CURLcode nss_load_key(struct connectdata *conn, int sockindex, status = PK11_Authenticate(slot, PR_TRUE, conn->data->set.str[STRING_KEY_PASSWD]); PK11_FreeSlot(slot); - return (SECSuccess == status) - ? CURLE_OK - : CURLE_SSL_CERTPROBLEM; + + return (SECSuccess == status) ? CURLE_OK : CURLE_SSL_CERTPROBLEM; } static int display_error(struct connectdata *conn, PRInt32 err, @@ -588,35 +592,35 @@ static CURLcode cert_stuff(struct connectdata *conn, int sockindex, char *cert_file, char *key_file) { struct SessionHandle *data = conn->data; - CURLcode rv; + CURLcode result; if(cert_file) { - rv = nss_load_cert(&conn->ssl[sockindex], cert_file, PR_FALSE); - if(CURLE_OK != rv) { + result = nss_load_cert(&conn->ssl[sockindex], cert_file, PR_FALSE); + if(result) { const PRErrorCode err = PR_GetError(); if(!display_error(conn, err, cert_file)) { const char *err_name = nss_error_to_name(err); failf(data, "unable to load client cert: %d (%s)", err, err_name); } - return rv; + return result; } } if(key_file || (is_file(cert_file))) { if(key_file) - rv = nss_load_key(conn, sockindex, key_file); + result = nss_load_key(conn, sockindex, key_file); else /* In case the cert file also has the key */ - rv = nss_load_key(conn, sockindex, cert_file); - if(CURLE_OK != rv) { + result = nss_load_key(conn, sockindex, cert_file); + if(result) { const PRErrorCode err = PR_GetError(); if(!display_error(conn, err, key_file)) { const char *err_name = nss_error_to_name(err); failf(data, "unable to load client key: %d (%s)", err, err_name); } - return rv; + return result; } } @@ -626,6 +630,7 @@ static CURLcode cert_stuff(struct connectdata *conn, int sockindex, static char * nss_get_password(PK11SlotInfo * slot, PRBool retry, void *arg) { (void)slot; /* unused */ + if(retry || NULL == arg) return NULL; else @@ -638,6 +643,34 @@ static SECStatus nss_auth_cert_hook(void *arg, PRFileDesc *fd, PRBool checksig, PRBool isServer) { struct connectdata *conn = (struct connectdata *)arg; + +#ifdef SSL_ENABLE_OCSP_STAPLING + if(conn->data->set.ssl.verifystatus) { + SECStatus cacheResult; + + const SECItemArray *csa = SSL_PeerStapledOCSPResponses(fd); + if(!csa) { + failf(conn->data, "Invalid OCSP response"); + return SECFailure; + } + + if(csa->len == 0) { + failf(conn->data, "No OCSP response received"); + return SECFailure; + } + + cacheResult = CERT_CacheOCSPResponseFromSideChannel( + CERT_GetDefaultCertDB(), SSL_PeerCertificate(fd), + PR_Now(), &csa->items[0], arg + ); + + if(cacheResult != SECSuccess) { + failf(conn->data, "Invalid OCSP response"); + return cacheResult; + } + } +#endif + if(!conn->data->set.ssl.verifypeer) { infof(conn->data, "skipping SSL peer certificate verification\n"); return SECSuccess; @@ -651,7 +684,6 @@ static SECStatus nss_auth_cert_hook(void *arg, PRFileDesc *fd, PRBool checksig, */ static void HandshakeCallback(PRFileDesc *sock, void *arg) { -#ifdef USE_NGHTTP2 struct connectdata *conn = (struct connectdata*) arg; unsigned int buflenmax = 50; unsigned char buf[50]; @@ -665,36 +697,94 @@ static void HandshakeCallback(PRFileDesc *sock, void *arg) if(SSL_GetNextProto(sock, &state, buf, &buflen, buflenmax) == SECSuccess) { switch(state) { - case SSL_NEXT_PROTO_NO_SUPPORT: - case SSL_NEXT_PROTO_NO_OVERLAP: - infof(conn->data, "TLS, neither ALPN nor NPN succeeded\n"); - return; + case SSL_NEXT_PROTO_NO_SUPPORT: + case SSL_NEXT_PROTO_NO_OVERLAP: + infof(conn->data, "ALPN/NPN, server did not agree to a protocol\n"); + return; #ifdef SSL_ENABLE_ALPN - case SSL_NEXT_PROTO_SELECTED: - infof(conn->data, "ALPN, server accepted to use %.*s\n", buflen, buf); - break; + case SSL_NEXT_PROTO_SELECTED: + infof(conn->data, "ALPN, server accepted to use %.*s\n", buflen, buf); + break; #endif - case SSL_NEXT_PROTO_NEGOTIATED: - infof(conn->data, "NPN, server accepted to use %.*s\n", buflen, buf); - break; + case SSL_NEXT_PROTO_NEGOTIATED: + infof(conn->data, "NPN, server accepted to use %.*s\n", buflen, buf); + break; } +#ifdef USE_NGHTTP2 if(buflen == NGHTTP2_PROTO_VERSION_ID_LEN && - memcmp(NGHTTP2_PROTO_VERSION_ID, buf, NGHTTP2_PROTO_VERSION_ID_LEN) - == 0) { - conn->negnpn = NPN_HTTP2; + !memcmp(NGHTTP2_PROTO_VERSION_ID, buf, NGHTTP2_PROTO_VERSION_ID_LEN)) { + conn->negnpn = CURL_HTTP_VERSION_2_0; } - else if(buflen == ALPN_HTTP_1_1_LENGTH && memcmp(ALPN_HTTP_1_1, buf, - ALPN_HTTP_1_1_LENGTH)) { - conn->negnpn = NPN_HTTP1_1; + else +#endif + if(buflen == ALPN_HTTP_1_1_LENGTH && + !memcmp(ALPN_HTTP_1_1, buf, ALPN_HTTP_1_1_LENGTH)) { + conn->negnpn = CURL_HTTP_VERSION_1_1; } } -#else - (void)sock; - (void)arg; -#endif } +#if NSSVERNUM >= 0x030f04 /* 3.15.4 */ +static SECStatus CanFalseStartCallback(PRFileDesc *sock, void *client_data, + PRBool *canFalseStart) +{ + struct connectdata *conn = client_data; + struct SessionHandle *data = conn->data; + + SSLChannelInfo channelInfo; + SSLCipherSuiteInfo cipherInfo; + + SECStatus rv; + PRBool negotiatedExtension; + + *canFalseStart = PR_FALSE; + + if(SSL_GetChannelInfo(sock, &channelInfo, sizeof(channelInfo)) != SECSuccess) + return SECFailure; + + if(SSL_GetCipherSuiteInfo(channelInfo.cipherSuite, &cipherInfo, + sizeof(cipherInfo)) != SECSuccess) + return SECFailure; + + /* Prevent version downgrade attacks from TLS 1.2, and avoid False Start for + * TLS 1.3 and later. See https://bugzilla.mozilla.org/show_bug.cgi?id=861310 + */ + if(channelInfo.protocolVersion != SSL_LIBRARY_VERSION_TLS_1_2) + goto end; + + /* Only allow ECDHE key exchange algorithm. + * See https://bugzilla.mozilla.org/show_bug.cgi?id=952863 */ + if(cipherInfo.keaType != ssl_kea_ecdh) + goto end; + + /* Prevent downgrade attacks on the symmetric cipher. We do not allow CBC + * mode due to BEAST, POODLE, and other attacks on the MAC-then-Encrypt + * design. See https://bugzilla.mozilla.org/show_bug.cgi?id=1109766 */ + if(cipherInfo.symCipher != ssl_calg_aes_gcm) + goto end; + + /* Enforce ALPN or NPN to do False Start, as an indicator of server + * compatibility. */ + rv = SSL_HandshakeNegotiatedExtension(sock, ssl_app_layer_protocol_xtn, + &negotiatedExtension); + if(rv != SECSuccess || !negotiatedExtension) { + rv = SSL_HandshakeNegotiatedExtension(sock, ssl_next_proto_nego_xtn, + &negotiatedExtension); + } + + if(rv != SECSuccess || !negotiatedExtension) + goto end; + + *canFalseStart = PR_TRUE; + + infof(data, "Trying TLS False Start\n"); + +end: + return SECSuccess; +} +#endif + static void display_cert_info(struct SessionHandle *data, CERTCertificate *cert) { @@ -723,8 +813,9 @@ static void display_cert_info(struct SessionHandle *data, PR_Free(common_name); } -static void display_conn_info(struct connectdata *conn, PRFileDesc *sock) +static CURLcode display_conn_info(struct connectdata *conn, PRFileDesc *sock) { + CURLcode result = CURLE_OK; SSLChannelInfo channel; SSLCipherSuiteInfo suite; CERTCertificate *cert; @@ -743,7 +834,6 @@ static void display_conn_info(struct connectdata *conn, PRFileDesc *sock) } cert = SSL_PeerCertificate(sock); - if(cert) { infof(conn->data, "Server certificate:\n"); @@ -768,21 +858,29 @@ static void display_conn_info(struct connectdata *conn, PRFileDesc *sock) cert2 = cert3; } } - Curl_ssl_init_certinfo(conn->data, i); - for(i = 0; cert; cert = cert2) { - Curl_extract_certinfo(conn, i++, (char *)cert->derCert.data, - (char *)cert->derCert.data + cert->derCert.len); - if(cert->isRoot) { + + result = Curl_ssl_init_certinfo(conn->data, i); + if(!result) { + for(i = 0; cert; cert = cert2) { + result = Curl_extract_certinfo(conn, i++, (char *)cert->derCert.data, + (char *)cert->derCert.data + + cert->derCert.len); + if(result) + break; + + if(cert->isRoot) { + CERT_DestroyCertificate(cert); + break; + } + + cert2 = CERT_FindCertIssuer(cert, now, certUsageSSLCA); CERT_DestroyCertificate(cert); - break; } - cert2 = CERT_FindCertIssuer(cert, now, certUsageSSLCA); - CERT_DestroyCertificate(cert); } } } - return; + return result; } static SECStatus BadCertHandler(void *arg, PRFileDesc *sock) @@ -820,7 +918,7 @@ static SECStatus BadCertHandler(void *arg, PRFileDesc *sock) static SECStatus check_issuer_cert(PRFileDesc *sock, char *issuer_nickname) { - CERTCertificate *cert,*cert_issuer,*issuer; + CERTCertificate *cert, *cert_issuer, *issuer; SECStatus res=SECSuccess; void *proto_win = NULL; @@ -831,7 +929,7 @@ static SECStatus check_issuer_cert(PRFileDesc *sock, */ cert = SSL_PeerCertificate(sock); - cert_issuer = CERT_FindCertIssuer(cert,PR_Now(),certUsageObjectSigner); + cert_issuer = CERT_FindCertIssuer(cert, PR_Now(), certUsageObjectSigner); proto_win = SSL_RevealPinArg(sock); issuer = PK11_FindCertFromNickname(issuer_nickname, proto_win); @@ -848,6 +946,53 @@ static SECStatus check_issuer_cert(PRFileDesc *sock, return res; } +static CURLcode cmp_peer_pubkey(struct ssl_connect_data *connssl, + const char *pinnedpubkey) +{ + CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH; + struct SessionHandle *data = connssl->data; + CERTCertificate *cert; + + if(!pinnedpubkey) + /* no pinned public key specified */ + return CURLE_OK; + + /* get peer certificate */ + cert = SSL_PeerCertificate(connssl->handle); + if(cert) { + /* extract public key from peer certificate */ + SECKEYPublicKey *pubkey = CERT_ExtractPublicKey(cert); + if(pubkey) { + /* encode the public key as DER */ + SECItem *cert_der = PK11_DEREncodePublicKey(pubkey); + if(cert_der) { + /* compare the public key with the pinned public key */ + result = Curl_pin_peer_pubkey(pinnedpubkey, + cert_der->data, + cert_der->len); + SECITEM_FreeItem(cert_der, PR_TRUE); + } + SECKEY_DestroyPublicKey(pubkey); + } + CERT_DestroyCertificate(cert); + } + + /* report the resulting status */ + switch(result) { + case CURLE_OK: + infof(data, "pinned public key verified successfully!\n"); + break; + case CURLE_SSL_PINNEDPUBKEYNOTMATCH: + failf(data, "failed to verify pinned public key"); + break; + default: + /* OOM, etc. */ + break; + } + + return result; +} + /** * * Callback to pick the SSL client certificate. @@ -935,36 +1080,6 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock, return SECSuccess; } -/* This function is supposed to decide, which error codes should be used - * to conclude server is TLS intolerant. - * - * taken from xulrunner - nsNSSIOLayer.cpp - */ -static PRBool -isTLSIntoleranceError(PRInt32 err) -{ - switch (err) { - case SSL_ERROR_BAD_MAC_ALERT: - case SSL_ERROR_BAD_MAC_READ: - case SSL_ERROR_HANDSHAKE_FAILURE_ALERT: - case SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT: - case SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE: - case SSL_ERROR_ILLEGAL_PARAMETER_ALERT: - case SSL_ERROR_NO_CYPHER_OVERLAP: - case SSL_ERROR_BAD_SERVER: - case SSL_ERROR_BAD_BLOCK_PADDING: - case SSL_ERROR_UNSUPPORTED_VERSION: - case SSL_ERROR_PROTOCOL_VERSION_ALERT: - case SSL_ERROR_RX_MALFORMED_FINISHED: - case SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE: - case SSL_ERROR_DECODE_ERROR_ALERT: - case SSL_ERROR_RX_UNKNOWN_ALERT: - return PR_TRUE; - default: - return PR_FALSE; - } -} - /* update blocking direction in case of PR_WOULD_BLOCK_ERROR */ static void nss_update_connecting_state(ssl_connect_state state, void *secret) { @@ -1019,6 +1134,7 @@ static PRStatus nspr_io_close(PRFileDesc *fd) return close_fn(fd); } +/* data might be NULL */ static CURLcode nss_init_core(struct SessionHandle *data, const char *cert_dir) { NSSInitParameters initparams; @@ -1056,11 +1172,12 @@ static CURLcode nss_init_core(struct SessionHandle *data, const char *cert_dir) return CURLE_SSL_CACERT_BADFILE; } +/* data might be NULL */ static CURLcode nss_init(struct SessionHandle *data) { char *cert_dir; struct_stat st; - CURLcode rv; + CURLcode result; if(initialized) return CURLE_OK; @@ -1102,14 +1219,15 @@ static CURLcode nss_init(struct SessionHandle *data) nspr_io_methods.close = nspr_io_close; } - rv = nss_init_core(data, cert_dir); - if(rv) - return rv; + result = nss_init_core(data, cert_dir); + if(result) + return result; if(num_enabled_ciphers() == 0) NSS_SetDomesticPolicy(); initialized = 1; + return CURLE_OK; } @@ -1133,20 +1251,22 @@ int Curl_nss_init(void) return 1; } +/* data might be NULL */ CURLcode Curl_nss_force_init(struct SessionHandle *data) { - CURLcode rv; + CURLcode result; if(!nss_initlock) { - failf(data, - "unable to initialize NSS, curl_global_init() should have been " - "called with CURL_GLOBAL_SSL or CURL_GLOBAL_ALL"); + if(data) + failf(data, "unable to initialize NSS, curl_global_init() should have " + "been called with CURL_GLOBAL_SSL or CURL_GLOBAL_ALL"); return CURLE_FAILED_INIT; } PR_Lock(nss_initlock); - rv = nss_init(data); + result = nss_init(data); PR_Unlock(nss_initlock); - return rv; + + return result; } /* Global cleanup */ @@ -1229,10 +1349,8 @@ void Curl_nss_close(struct connectdata *conn, int sockindex) * authentication data from a previous connection. */ SSL_InvalidateSession(connssl->handle); - if(connssl->client_nickname != NULL) { - free(connssl->client_nickname); - connssl->client_nickname = NULL; - } + free(connssl->client_nickname); + connssl->client_nickname = NULL; /* destroy all NSS objects in order to avoid failure of NSS shutdown */ Curl_llist_destroy(connssl->obj_list, NULL); connssl->obj_list = NULL; @@ -1243,16 +1361,6 @@ void Curl_nss_close(struct connectdata *conn, int sockindex) } } -/* - * This function is called when the 'data' struct is going away. Close - * down everything and free all resources! - */ -int Curl_nss_close_all(struct SessionHandle *data) -{ - (void)data; - return 0; -} - /* return true if NSS can provide error code (and possibly msg) for the error */ static bool is_nss_error(CURLcode err) @@ -1295,9 +1403,9 @@ static CURLcode nss_load_ca_certificates(struct connectdata *conn, const char *capath = data->set.ssl.CApath; if(cafile) { - CURLcode rv = nss_load_cert(&conn->ssl[sockindex], cafile, PR_TRUE); - if(CURLE_OK != rv) - return rv; + CURLcode result = nss_load_cert(&conn->ssl[sockindex], cafile, PR_TRUE); + if(result) + return result; } if(capath) { @@ -1342,18 +1450,11 @@ static CURLcode nss_load_ca_certificates(struct connectdata *conn, static CURLcode nss_init_sslver(SSLVersionRange *sslver, struct SessionHandle *data) { - switch (data->set.ssl.version) { + switch(data->set.ssl.version) { default: case CURL_SSLVERSION_DEFAULT: - sslver->min = SSL_LIBRARY_VERSION_3_0; - if(data->state.ssl_connect_retry) { - infof(data, "TLS disabled due to previous handshake failure\n"); - sslver->max = SSL_LIBRARY_VERSION_3_0; - return CURLE_OK; - } - /* intentional fall-through to default to highest TLS version if possible */ - case CURL_SSLVERSION_TLSv1: + sslver->min = SSL_LIBRARY_VERSION_TLS_1_0; #ifdef SSL_LIBRARY_VERSION_TLS_1_2 sslver->max = SSL_LIBRARY_VERSION_TLS_1_2; #elif defined SSL_LIBRARY_VERSION_TLS_1_1 @@ -1403,12 +1504,8 @@ static CURLcode nss_fail_connect(struct ssl_connect_data *connssl, struct SessionHandle *data, CURLcode curlerr) { - SSLVersionRange sslver; PRErrorCode err = 0; - /* reset the flag to avoid an infinite loop */ - data->state.ssl_connect_retry = FALSE; - if(is_nss_error(curlerr)) { /* read NSPR error code */ err = PR_GetError(); @@ -1426,17 +1523,6 @@ static CURLcode nss_fail_connect(struct ssl_connect_data *connssl, Curl_llist_destroy(connssl->obj_list, NULL); connssl->obj_list = NULL; - if(connssl->handle - && (SSL_VersionRangeGet(connssl->handle, &sslver) == SECSuccess) - && (sslver.min == SSL_LIBRARY_VERSION_3_0) - && (sslver.max != SSL_LIBRARY_VERSION_3_0) - && isTLSIntoleranceError(err)) { - /* schedule reconnect through Curl_retry_request() */ - data->state.ssl_connect_retry = TRUE; - infof(data, "Error in TLS handshake, trying SSLv3...\n"); - return CURLE_OK; - } - return curlerr; } @@ -1464,27 +1550,13 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) struct SessionHandle *data = conn->data; curl_socket_t sockfd = conn->sock[sockindex]; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - CURLcode curlerr; + CURLcode result; SSLVersionRange sslver = { SSL_LIBRARY_VERSION_TLS_1_0, /* min */ SSL_LIBRARY_VERSION_TLS_1_0 /* max */ }; -#ifdef USE_NGHTTP2 -#if defined(SSL_ENABLE_NPN) || defined(SSL_ENABLE_ALPN) - unsigned int alpn_protos_len = NGHTTP2_PROTO_VERSION_ID_LEN + - ALPN_HTTP_1_1_LENGTH + 2; - unsigned char alpn_protos[NGHTTP2_PROTO_VERSION_ID_LEN + ALPN_HTTP_1_1_LENGTH - + 2]; - int cur = 0; -#endif -#endif - - - if(connssl->state == ssl_connection_complete) - return CURLE_OK; - connssl->data = data; /* list of all NSS objects we need to destroy in Curl_nss_close() */ @@ -1494,13 +1566,13 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) /* FIXME. NSS doesn't support multiple databases open at the same time. */ PR_Lock(nss_initlock); - curlerr = nss_init(conn->data); - if(CURLE_OK != curlerr) { + result = nss_init(conn->data); + if(result) { PR_Unlock(nss_initlock); goto error; } - curlerr = CURLE_SSL_CONNECT_ERROR; + result = CURLE_SSL_CONNECT_ERROR; if(!mod) { char *configstring = aprintf("library=%s name=PEM", pem_library); @@ -1517,7 +1589,7 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) mod = NULL; } infof(data, "WARNING: failed to load NSS PEM library %s. Using " - "OpenSSL PEM certificates will not work.\n", pem_library); + "OpenSSL PEM certificates will not work.\n", pem_library); } } @@ -1560,12 +1632,9 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) infof(data, "warning: support for SSL_CBC_RANDOM_IV not compiled in\n"); #endif - /* reset the flag to avoid an infinite loop */ - data->state.ssl_connect_retry = FALSE; - if(data->set.ssl.cipher_list) { if(set_ciphers(data, model, data->set.ssl.cipher_list) != SECSuccess) { - curlerr = CURLE_SSL_CIPHER; + result = CURLE_SSL_CIPHER; goto error; } } @@ -1587,16 +1656,16 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) if(data->set.ssl.verifypeer) { const CURLcode rv = nss_load_ca_certificates(conn, sockindex); - if(CURLE_OK != rv) { - curlerr = rv; + if(rv) { + result = rv; goto error; } } if(data->set.ssl.CRLfile) { const CURLcode rv = nss_load_crl(data->set.ssl.CRLfile); - if(CURLE_OK != rv) { - curlerr = rv; + if(rv) { + result = rv; goto error; } infof(data, " CRLfile: %s\n", data->set.ssl.CRLfile); @@ -1611,9 +1680,9 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) else { CURLcode rv = cert_stuff(conn, sockindex, data->set.str[STRING_CERT], data->set.str[STRING_KEY]); - if(CURLE_OK != rv) { + if(rv) { /* failf() is already done in cert_stuff() */ - curlerr = rv; + result = rv; goto error; } } @@ -1626,7 +1695,7 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) if(SSL_GetClientAuthDataHook(model, SelectClientCert, (void *)connssl) != SECSuccess) { - curlerr = CURLE_SSL_CERTPROBLEM; + result = CURLE_SSL_CERTPROBLEM; goto error; } @@ -1667,42 +1736,57 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) SSL_SetPKCS11PinArg(connssl->handle, data->set.str[STRING_KEY_PASSWD]); } -#ifdef USE_NGHTTP2 - if(data->set.httpversion == CURL_HTTP_VERSION_2_0) { +#ifdef SSL_ENABLE_OCSP_STAPLING + if(data->set.ssl.verifystatus) { + if(SSL_OptionSet(connssl->handle, SSL_ENABLE_OCSP_STAPLING, PR_TRUE) + != SECSuccess) + goto error; + } +#endif + #ifdef SSL_ENABLE_NPN - if(data->set.ssl_enable_npn) { - if(SSL_OptionSet(connssl->handle, SSL_ENABLE_NPN, PR_TRUE) != SECSuccess) - goto error; - } + if(SSL_OptionSet(connssl->handle, SSL_ENABLE_NPN, data->set.ssl_enable_npn + ? PR_TRUE : PR_FALSE) != SECSuccess) + goto error; #endif #ifdef SSL_ENABLE_ALPN - if(data->set.ssl_enable_alpn) { - if(SSL_OptionSet(connssl->handle, SSL_ENABLE_ALPN, PR_TRUE) - != SECSuccess) - goto error; - } + if(SSL_OptionSet(connssl->handle, SSL_ENABLE_ALPN, data->set.ssl_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) + != SECSuccess) + goto error; + + if(SSL_SetCanFalseStartCallback(connssl->handle, CanFalseStartCallback, + conn) != SECSuccess) + goto error; + } #endif #if defined(SSL_ENABLE_NPN) || defined(SSL_ENABLE_ALPN) - if(data->set.ssl_enable_npn || data->set.ssl_enable_alpn) { - alpn_protos[cur] = NGHTTP2_PROTO_VERSION_ID_LEN; - cur++; - memcpy(&alpn_protos[cur], NGHTTP2_PROTO_VERSION_ID, + if(data->set.ssl_enable_npn || data->set.ssl_enable_alpn) { + int cur = 0; + unsigned char protocols[128]; + +#ifdef USE_NGHTTP2 + if(data->set.httpversion == CURL_HTTP_VERSION_2_0) { + protocols[cur++] = NGHTTP2_PROTO_VERSION_ID_LEN; + memcpy(&protocols[cur], NGHTTP2_PROTO_VERSION_ID, NGHTTP2_PROTO_VERSION_ID_LEN); cur += NGHTTP2_PROTO_VERSION_ID_LEN; - alpn_protos[cur] = ALPN_HTTP_1_1_LENGTH; - cur++; - memcpy(&alpn_protos[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH); - - if(SSL_SetNextProtoNego(connssl->handle, alpn_protos, alpn_protos_len) - != SECSuccess) - goto error; - } - else { - infof(data, "SSL, can't negotiate HTTP/2.0 with neither NPN nor ALPN\n"); } #endif + protocols[cur++] = ALPN_HTTP_1_1_LENGTH; + 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) + goto error; } #endif @@ -1718,21 +1802,21 @@ error: if(model) PR_Close(model); - return nss_fail_connect(connssl, data, curlerr); + return nss_fail_connect(connssl, data, result); } static CURLcode nss_do_connect(struct connectdata *conn, int sockindex) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; struct SessionHandle *data = conn->data; - CURLcode curlerr = CURLE_SSL_CONNECT_ERROR; + CURLcode result = CURLE_SSL_CONNECT_ERROR; PRUint32 timeout; /* check timeout situation */ const long time_left = Curl_timeleft(data, NULL, TRUE); if(time_left < 0L) { failf(data, "timed out before SSL handshake"); - curlerr = CURLE_OPERATION_TIMEDOUT; + result = CURLE_OPERATION_TIMEDOUT; goto error; } @@ -1743,17 +1827,15 @@ static CURLcode nss_do_connect(struct connectdata *conn, int sockindex) /* blocking direction is updated by nss_update_connecting_state() */ return CURLE_AGAIN; else if(conn->data->set.ssl.certverifyresult == SSL_ERROR_BAD_CERT_DOMAIN) - curlerr = CURLE_PEER_FAILED_VERIFICATION; + result = CURLE_PEER_FAILED_VERIFICATION; else if(conn->data->set.ssl.certverifyresult!=0) - curlerr = CURLE_SSL_CACERT; + result = CURLE_SSL_CACERT; goto error; } - connssl->state = ssl_connection_complete; - conn->recv[sockindex] = nss_recv; - conn->send[sockindex] = nss_send; - - display_conn_info(conn, connssl->handle); + result = display_conn_info(conn, connssl->handle); + if(result) + goto error; if(data->set.str[STRING_SSL_ISSUERCERT]) { SECStatus ret = SECFailure; @@ -1765,8 +1847,8 @@ static CURLcode nss_do_connect(struct connectdata *conn, int sockindex) } if(SECFailure == ret) { - infof(data,"SSL certificate issuer check failed\n"); - curlerr = CURLE_SSL_ISSUER_ERROR; + infof(data, "SSL certificate issuer check failed\n"); + result = CURLE_SSL_ISSUER_ERROR; goto error; } else { @@ -1774,10 +1856,15 @@ static CURLcode nss_do_connect(struct connectdata *conn, int sockindex) } } + result = cmp_peer_pubkey(connssl, data->set.str[STRING_SSL_PINNEDPUBLICKEY]); + if(result) + /* status already printed */ + goto error; + return CURLE_OK; error: - return nss_fail_connect(connssl, data, curlerr); + return nss_fail_connect(connssl, data, result); } static CURLcode nss_connect_common(struct connectdata *conn, int sockindex, @@ -1786,26 +1873,29 @@ static CURLcode nss_connect_common(struct connectdata *conn, int sockindex, struct ssl_connect_data *connssl = &conn->ssl[sockindex]; struct SessionHandle *data = conn->data; const bool blocking = (done == NULL); - CURLcode rv; + CURLcode result; + + if(connssl->state == ssl_connection_complete) + return CURLE_OK; if(connssl->connecting_state == ssl_connect_1) { - rv = nss_setup_connect(conn, sockindex); - if(rv) + result = nss_setup_connect(conn, sockindex); + if(result) /* we do not expect CURLE_AGAIN from nss_setup_connect() */ - return rv; + return result; if(!blocking) { /* in non-blocking mode, set NSS non-blocking mode before handshake */ - rv = nss_set_nonblock(connssl, data); - if(rv) - return rv; + result = nss_set_nonblock(connssl, data); + if(result) + return result; } connssl->connecting_state = ssl_connect_2; } - rv = nss_do_connect(conn, sockindex); - switch(rv) { + result = nss_do_connect(conn, sockindex); + switch(result) { case CURLE_OK: break; case CURLE_AGAIN: @@ -1814,20 +1904,26 @@ static CURLcode nss_connect_common(struct connectdata *conn, int sockindex, return CURLE_OK; /* fall through */ default: - return rv; + return result; } if(blocking) { /* in blocking mode, set NSS non-blocking mode _after_ SSL handshake */ - rv = nss_set_nonblock(connssl, data); - if(rv) - return rv; + result = nss_set_nonblock(connssl, data); + if(result) + return result; } else /* signal completed SSL handshake */ *done = TRUE; - connssl->connecting_state = ssl_connect_done; + connssl->state = ssl_connection_complete; + conn->recv[sockindex] = nss_recv; + conn->send[sockindex] = nss_send; + + /* ssl_connect_done is never used outside, go back to the initial state */ + connssl->connecting_state = ssl_connect_1; + return CURLE_OK; } @@ -1866,8 +1962,10 @@ static ssize_t nss_send(struct connectdata *conn, /* connection data */ ? CURLE_SSL_CERTPROBLEM : CURLE_SEND_ERROR; } + return -1; } + return rc; /* number of bytes */ } @@ -1897,8 +1995,10 @@ static ssize_t nss_recv(struct connectdata * conn, /* connection data */ ? CURLE_SSL_CERTPROBLEM : CURLE_RECV_ERROR; } + return -1; } + return nread; } @@ -1907,6 +2007,7 @@ 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 SessionHandle *data) { /* make sure that NSS is initialized */ @@ -1918,13 +2019,12 @@ int Curl_nss_random(struct SessionHandle *data, unsigned char *entropy, size_t length) { - if(data) - Curl_nss_seed(data); /* Initiate the seed if not already done */ - if(SECSuccess != PK11_GenerateRandom(entropy, curlx_uztosi(length))) { - /* no way to signal a failure from here, we have to abort */ - failf(data, "PK11_GenerateRandom() failed, calling abort()..."); - abort(); - } + Curl_nss_seed(data); /* Initiate the seed if not already done */ + + if(SECSuccess != PK11_GenerateRandom(entropy, curlx_uztosi(length))) + /* signal a failure */ + return -1; + return 0; } @@ -1935,9 +2035,40 @@ void Curl_nss_md5sum(unsigned char *tmp, /* input */ { PK11Context *MD5pw = PK11_CreateDigestContext(SEC_OID_MD5); unsigned int MD5out; + PK11_DigestOp(MD5pw, tmp, curlx_uztoui(tmplen)); PK11_DigestFinal(MD5pw, md5sum, &MD5out, curlx_uztoui(md5len)); PK11_DestroyContext(MD5pw, PR_TRUE); } +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; + + PK11_DigestOp(SHA256pw, tmp, curlx_uztoui(tmplen)); + PK11_DigestFinal(SHA256pw, sha256sum, &SHA256out, curlx_uztoui(sha256len)); + PK11_DestroyContext(SHA256pw, PR_TRUE); +} + +bool Curl_nss_cert_status_request(void) +{ +#ifdef SSL_ENABLE_OCSP_STAPLING + return TRUE; +#else + return FALSE; +#endif +} + +bool Curl_nss_false_start(void) { +#if NSSVERNUM >= 0x030f04 /* 3.15.4 */ + return TRUE; +#else + return FALSE; +#endif +} + #endif /* USE_NSS */ diff --git a/Utilities/cmcurl/lib/vtls/nssg.h b/Utilities/cmcurl/lib/vtls/nssg.h index 311f873..5fd7275 100644 --- a/Utilities/cmcurl/lib/vtls/nssg.h +++ b/Utilities/cmcurl/lib/vtls/nssg.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -37,10 +37,6 @@ CURLcode Curl_nss_connect_nonblocking(struct connectdata *conn, /* close a SSL connection */ void Curl_nss_close(struct connectdata *conn, int sockindex); -/* tell NSS to close down all open information regarding connections (and - thus session ID caching etc) */ -int Curl_nss_close_all(struct SessionHandle *data); - int Curl_nss_init(void); void Curl_nss_cleanup(void); @@ -60,8 +56,23 @@ void Curl_nss_md5sum(unsigned char *tmp, /* input */ unsigned char *md5sum, /* output */ size_t md5len); -/* this backend provides these functions: */ -#define have_curlssl_md5sum 1 +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); + +/* 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 /* API setup for NSS */ #define curlssl_init Curl_nss_init @@ -71,19 +82,21 @@ void Curl_nss_md5sum(unsigned char *tmp, /* input */ /* NSS has its own session ID cache */ #define curlssl_session_free(x) Curl_nop_stmt -#define curlssl_close_all Curl_nss_close_all +#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) (x=x, y=y, 1) -#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_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) (x=x, y=y, 0) +#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 CURL_SSL_BACKEND CURLSSLBACKEND_NSS +#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() #endif /* USE_NSS */ #endif /* HEADER_CURL_NSSG_H */ diff --git a/Utilities/cmcurl/lib/vtls/openssl.c b/Utilities/cmcurl/lib/vtls/openssl.c index da92854..90e4c2b 100644 --- a/Utilities/cmcurl/lib/vtls/openssl.c +++ b/Utilities/cmcurl/lib/vtls/openssl.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -32,6 +32,8 @@ #include "curl_setup.h" +#ifdef USE_OPENSSL + #ifdef HAVE_LIMITS_H #include <limits.h> #endif @@ -49,13 +51,9 @@ #include "vtls.h" #include "rawstr.h" #include "hostcheck.h" +#include "curl_printf.h" -#define _MPRINTF_REPLACE /* use the internal *printf() functions */ -#include <curl/mprintf.h> - -#ifdef USE_SSLEAY - -#ifdef USE_OPENSSL +#include <openssl/ssl.h> #include <openssl/rand.h> #include <openssl/x509v3.h> #include <openssl/dsa.h> @@ -63,36 +61,29 @@ #include <openssl/err.h> #include <openssl/md5.h> #include <openssl/conf.h> -#else -#include <rand.h> -#include <x509v3.h> -#include <md5.h> +#include <openssl/bn.h> +#include <openssl/rsa.h> + +#ifdef HAVE_OPENSSL_PKCS12_H +#include <openssl/pkcs12.h> +#endif + +#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_IS_BORINGSSL) +#include <openssl/ocsp.h> #endif #include "warnless.h" -#include "curl_memory.h" #include "non-ascii.h" /* for Curl_convert_from_utf8 prototype */ -/* The last #include file should be: */ +/* The last #include files should be: */ +#include "curl_memory.h" #include "memdebug.h" #ifndef OPENSSL_VERSION_NUMBER #error "OPENSSL_VERSION_NUMBER not defined" #endif -#if OPENSSL_VERSION_NUMBER >= 0x0090581fL -#define HAVE_SSL_GET1_SESSION 1 -#else -#undef HAVE_SSL_GET1_SESSION -#endif - -#if OPENSSL_VERSION_NUMBER >= 0x00904100L -#define HAVE_USERDATA_IN_PWD_CALLBACK 1 -#else -#undef HAVE_USERDATA_IN_PWD_CALLBACK -#endif - -#if OPENSSL_VERSION_NUMBER >= 0x00907001L +#if OPENSSL_VERSION_NUMBER >= 0x00907001L && !defined(OPENSSL_IS_BORINGSSL) /* ENGINE_load_private_key() takes four arguments */ #define HAVE_ENGINE_LOAD_FOUR_ARGS #include <openssl/ui.h> @@ -101,18 +92,16 @@ #undef HAVE_ENGINE_LOAD_FOUR_ARGS #endif -#if (OPENSSL_VERSION_NUMBER >= 0x00903001L) && defined(HAVE_OPENSSL_PKCS12_H) -/* OpenSSL has PKCS 12 support */ +#if (OPENSSL_VERSION_NUMBER >= 0x00903001L) && \ + defined(HAVE_OPENSSL_PKCS12_H) && \ + !defined(OPENSSL_IS_BORINGSSL) +/* OpenSSL has PKCS 12 support, BoringSSL does not */ #define HAVE_PKCS12_SUPPORT #else -/* OpenSSL/SSLEay does not have PKCS12 support */ +/* OpenSSL does not have PKCS12 support */ #undef HAVE_PKCS12_SUPPORT #endif -#if OPENSSL_VERSION_NUMBER >= 0x00906001L -#define HAVE_ERR_ERROR_STRING_N 1 -#endif - #if OPENSSL_VERSION_NUMBER >= 0x00909000L #define SSL_METHOD_QUAL const #else @@ -126,15 +115,32 @@ #define X509_STORE_set_flags(x,y) Curl_nop_stmt #endif -#if OPENSSL_VERSION_NUMBER >= 0x10000000L +#ifdef OPENSSL_IS_BORINGSSL +/* BoringSSL has no ERR_remove_state() */ +#define ERR_remove_state(x) +#elif (OPENSSL_VERSION_NUMBER >= 0x10000000L) #define HAVE_ERR_REMOVE_THREAD_STATE 1 #endif -#ifndef HAVE_SSLV2_CLIENT_METHOD +#if !defined(HAVE_SSLV2_CLIENT_METHOD) || \ + OPENSSL_VERSION_NUMBER >= 0x10100000L /* 1.1.0+ has no SSLv2 */ #undef OPENSSL_NO_SSL2 /* undef first to avoid compiler warnings */ #define OPENSSL_NO_SSL2 #endif +#if defined(OPENSSL_IS_BORINGSSL) +#define NO_RAND_SEED 1 +/* In BoringSSL OpenSSL_add_all_algorithms does nothing */ +#define OpenSSL_add_all_algorithms() +/* BoringSSL does not have CONF_modules_load_file */ +#define CONF_modules_load_file(a,b,c) +#endif + +#if (OPENSSL_VERSION_NUMBER < 0x0090808fL) || defined(OPENSSL_IS_BORINGSSL) +/* not present in BoringSSL or older OpenSSL */ +#define OPENSSL_load_builtin_modules(x) +#endif + /* * 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 @@ -143,18 +149,8 @@ */ #define RAND_LOAD_LENGTH 1024 -#ifndef HAVE_USERDATA_IN_PWD_CALLBACK -static char global_passwd[64]; -#endif - -static int passwd_callback(char *buf, int num, int encrypting -#ifdef HAVE_USERDATA_IN_PWD_CALLBACK - /* This was introduced in 0.9.4, we can set this - using SSL_CTX_set_default_passwd_cb_userdata() - */ - , void *global_passwd -#endif - ) +static int passwd_callback(char *buf, int num, int encrypting, + void *global_passwd) { DEBUGASSERT(0 == encrypting); @@ -175,6 +171,7 @@ static int passwd_callback(char *buf, int num, int encrypting * pass in an argument that is never used. */ +#ifndef NO_RAND_SEED #ifdef HAVE_RAND_STATUS #define seed_enough(x) rand_enough() static bool rand_enough(void) @@ -259,7 +256,7 @@ static int ossl_seed(struct SessionHandle *data) return nread; } -static int Curl_ossl_seed(struct SessionHandle *data) +static void Curl_ossl_seed(struct SessionHandle *data) { /* we have the "SSL is seeded" boolean static to prevent multiple time-consuming seedings in vain */ @@ -270,8 +267,11 @@ static int Curl_ossl_seed(struct SessionHandle *data) ossl_seed(data); ssl_seeded = TRUE; } - return 0; } +#else +/* BoringSSL needs no seeding */ +#define Curl_ossl_seed(x) +#endif #ifndef SSL_FILETYPE_ENGINE @@ -308,8 +308,7 @@ static int ssl_ui_reader(UI *ui, UI_STRING *uis) case UIT_PROMPT: case UIT_VERIFY: password = (const char*)UI_get0_user_data(ui); - if(NULL != password && - UI_get_input_flags(uis) & UI_INPUT_FLAG_DEFAULT_PWD) { + if(password && (UI_get_input_flags(uis) & UI_INPUT_FLAG_DEFAULT_PWD)) { UI_set_result(ui, uis, password); return 1; } @@ -327,8 +326,8 @@ static int ssl_ui_writer(UI *ui, UI_STRING *uis) switch(UI_get_string_type(uis)) { case UIT_PROMPT: case UIT_VERIFY: - if(NULL != UI_get0_user_data(ui) && - UI_get_input_flags(uis) & UI_INPUT_FLAG_DEFAULT_PWD) { + if(UI_get0_user_data(ui) && + (UI_get_input_flags(uis) & UI_INPUT_FLAG_DEFAULT_PWD)) { return 1; } default: @@ -350,43 +349,29 @@ int cert_stuff(struct connectdata *conn, int file_type = do_file_type(cert_type); - if(cert_file != NULL || file_type == SSL_FILETYPE_ENGINE) { + if(cert_file || (file_type == SSL_FILETYPE_ENGINE)) { SSL *ssl; X509 *x509; int cert_done = 0; if(data->set.str[STRING_KEY_PASSWD]) { -#ifndef HAVE_USERDATA_IN_PWD_CALLBACK - /* - * If password has been given, we store that in the global - * area (*shudder*) for a while: - */ - size_t len = strlen(data->set.str[STRING_KEY_PASSWD]); - if(len < sizeof(global_passwd)) - memcpy(global_passwd, data->set.str[STRING_KEY_PASSWD], len+1); - else - global_passwd[0] = '\0'; -#else - /* - * We set the password in the callback userdata - */ + /* set the password in the callback userdata */ SSL_CTX_set_default_passwd_cb_userdata(ctx, data->set.str[STRING_KEY_PASSWD]); -#endif /* Set passwd callback: */ SSL_CTX_set_default_passwd_cb(ctx, passwd_callback); } -#define SSL_CLIENT_CERT_ERR \ - "unable to use client certificate (no key found or wrong pass phrase?)" - switch(file_type) { case SSL_FILETYPE_PEM: /* SSL_CTX_use_certificate_chain_file() only works on PEM files */ if(SSL_CTX_use_certificate_chain_file(ctx, cert_file) != 1) { - failf(data, SSL_CLIENT_CERT_ERR); + failf(data, + "could not load PEM client certificate, OpenSSL error %s, " + "(no key found, wrong pass phrase, or wrong file format?)", + ERR_error_string(ERR_get_error(), NULL) ); return 0; } break; @@ -398,7 +383,10 @@ int cert_stuff(struct connectdata *conn, if(SSL_CTX_use_certificate_file(ctx, cert_file, file_type) != 1) { - failf(data, SSL_CLIENT_CERT_ERR); + failf(data, + "could not load ASN1 client certificate, OpenSSL error %s, " + "(no key found, wrong pass phrase, or wrong file format?)", + ERR_error_string(ERR_get_error(), NULL) ); return 0; } break; @@ -464,7 +452,7 @@ int cert_stuff(struct connectdata *conn, STACK_OF(X509) *ca = NULL; int i; - f = fopen(cert_file,"rb"); + f = fopen(cert_file, "rb"); if(!f) { failf(data, "could not open PKCS12 file '%s'", cert_file); return 0; @@ -473,7 +461,7 @@ int cert_stuff(struct connectdata *conn, fclose(f); if(!p12) { - failf(data, "error reading PKCS12 file '%s'", cert_file ); + failf(data, "error reading PKCS12 file '%s'", cert_file); return 0; } @@ -491,7 +479,9 @@ int cert_stuff(struct connectdata *conn, PKCS12_free(p12); if(SSL_CTX_use_certificate(ctx, x509) != 1) { - failf(data, SSL_CLIENT_CERT_ERR); + failf(data, + "could not load PKCS12 client certificate, OpenSSL error %s", + ERR_error_string(ERR_get_error(), NULL) ); goto fail; } @@ -556,7 +546,7 @@ int cert_stuff(struct connectdata *conn, case SSL_FILETYPE_PEM: if(cert_done) break; - if(key_file == NULL) + if(!key_file) /* cert & key can only be in PEM case in the same file */ key_file=cert_file; case SSL_FILETYPE_ASN1: @@ -574,7 +564,7 @@ int cert_stuff(struct connectdata *conn, #ifdef HAVE_ENGINE_LOAD_FOUR_ARGS UI_METHOD *ui_method = UI_create_method((char *)"cURL user interface"); - if(NULL == ui_method) { + if(!ui_method) { failf(data, "unable do create OpenSSL user-interface method"); return 0; } @@ -585,7 +575,7 @@ int cert_stuff(struct connectdata *conn, #endif /* the typecast below was added to please mingw32 */ priv_key = (EVP_PKEY *) - ENGINE_load_private_key(data->state.engine,key_file, + ENGINE_load_private_key(data->state.engine, key_file, #ifdef HAVE_ENGINE_LOAD_FOUR_ARGS ui_method, #endif @@ -626,8 +616,8 @@ int cert_stuff(struct connectdata *conn, } ssl=SSL_new(ctx); - if(NULL == ssl) { - failf(data,"unable to create an SSL structure"); + if(!ssl) { + failf(data, "unable to create an SSL structure"); return 0; } @@ -635,9 +625,9 @@ int cert_stuff(struct connectdata *conn, /* This version was provided by Evan Jordan and is supposed to not leak memory as the previous version: */ - if(x509 != NULL) { + if(x509) { EVP_PKEY *pktmp = X509_get_pubkey(x509); - EVP_PKEY_copy_parameters(pktmp,SSL_get_privatekey(ssl)); + EVP_PKEY_copy_parameters(pktmp, SSL_get_privatekey(ssl)); EVP_PKEY_free(pktmp); } @@ -653,10 +643,6 @@ int cert_stuff(struct connectdata *conn, failf(data, "Private key does not match the certificate public key"); return 0; } -#ifndef HAVE_USERDATA_IN_PWD_CALLBACK - /* erase it now */ - memset(global_passwd, 0, sizeof(global_passwd)); -#endif } return 1; } @@ -691,36 +677,17 @@ static int x509_name_oneline(X509_NAME *a, char *buf, size_t size) #endif } -static -int cert_verify_callback(int ok, X509_STORE_CTX *ctx) -{ - X509 *err_cert; - char buf[256]; - - err_cert=X509_STORE_CTX_get_current_cert(ctx); - (void)x509_name_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf)); - return ok; -} - /* Return error string for last OpenSSL error */ static char *SSL_strerror(unsigned long error, char *buf, size_t size) { -#ifdef HAVE_ERR_ERROR_STRING_N /* OpenSSL 0.9.6 and later has a function named - ERRO_error_string_n() that takes the size of the buffer as a + ERR_error_string_n() that takes the size of the buffer as a third argument */ ERR_error_string_n(error, buf, size); -#else - (void) size; - ERR_error_string(error, buf); -#endif return buf; } -#endif /* USE_SSLEAY */ - -#ifdef USE_SSLEAY /** * Global SSL init * @@ -729,6 +696,8 @@ static char *SSL_strerror(unsigned long error, char *buf, size_t size) */ int Curl_ossl_init(void) { + OPENSSL_load_builtin_modules(); + #ifdef HAVE_ENGINE_LOAD_BUILTIN_ENGINES ENGINE_load_builtin_engines(); #endif @@ -749,17 +718,19 @@ int Curl_ossl_init(void) calls CONF_modules_load_file() and we use that instead and we ignore its return code! */ - (void)CONF_modules_load_file(NULL, NULL, - CONF_MFLAGS_DEFAULT_SECTION| - CONF_MFLAGS_IGNORE_MISSING_FILE); + /* CONF_MFLAGS_DEFAULT_SECTION introduced some time between 0.9.8b and + 0.9.8e */ +#ifndef CONF_MFLAGS_DEFAULT_SECTION +#define CONF_MFLAGS_DEFAULT_SECTION 0x0 +#endif + + CONF_modules_load_file(NULL, NULL, + CONF_MFLAGS_DEFAULT_SECTION| + CONF_MFLAGS_IGNORE_MISSING_FILE); return 1; } -#endif /* USE_SSLEAY */ - -#ifdef USE_SSLEAY - /* Global cleanup */ void Curl_ossl_cleanup(void) { @@ -814,7 +785,7 @@ int Curl_ossl_check_cxn(struct connectdata *conn) */ CURLcode Curl_ossl_set_engine(struct SessionHandle *data, const char *engine) { -#if defined(USE_SSLEAY) && defined(HAVE_OPENSSL_ENGINE_H) +#if defined(USE_OPENSSL) && defined(HAVE_OPENSSL_ENGINE_H) ENGINE *e; #if OPENSSL_VERSION_NUMBER >= 0x00909000L @@ -862,7 +833,7 @@ CURLcode Curl_ossl_set_engine_default(struct SessionHandle *data) #ifdef HAVE_OPENSSL_ENGINE_H if(data->state.engine) { if(ENGINE_set_default(data->state.engine, ENGINE_METHOD_ALL) > 0) { - infof(data,"set default crypto engine '%s'\n", + infof(data, "set default crypto engine '%s'\n", ENGINE_get_id(data->state.engine)); } else { @@ -882,7 +853,7 @@ CURLcode Curl_ossl_set_engine_default(struct SessionHandle *data) struct curl_slist *Curl_ossl_engines_list(struct SessionHandle *data) { struct curl_slist *list = NULL; -#if defined(USE_SSLEAY) && defined(HAVE_OPENSSL_ENGINE_H) +#if defined(USE_OPENSSL) && defined(HAVE_OPENSSL_ENGINE_H) struct curl_slist *beg; ENGINE *e; @@ -1031,7 +1002,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! */ -int Curl_ossl_close_all(struct SessionHandle *data) +void Curl_ossl_close_all(struct SessionHandle *data) { #ifdef HAVE_OPENSSL_ENGINE_H if(data->state.engine) { @@ -1042,7 +1013,6 @@ int Curl_ossl_close_all(struct SessionHandle *data) #else (void)data; #endif - return 0; } static int asn1_output(const ASN1_UTCTIME *tm, @@ -1052,7 +1022,7 @@ static int asn1_output(const ASN1_UTCTIME *tm, const char *asn1_string; int gmt=FALSE; int i; - int year=0,month=0,day=0,hour=0,minute=0,second=0; + int year=0, month=0, day=0, hour=0, minute=0, second=0; i=tm->length; asn1_string=(const char *)tm->data; @@ -1112,8 +1082,7 @@ static int asn1_output(const ASN1_UTCTIME *tm, in the certificate and must exactly match the IP in the URI. */ -static CURLcode verifyhost(struct connectdata *conn, - X509 *server_cert) +static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert) { int matched = -1; /* -1 is no alternative match yet, 1 means match and 0 means mismatch */ @@ -1126,7 +1095,7 @@ static CURLcode verifyhost(struct connectdata *conn, #else struct in_addr addr; #endif - CURLcode res = CURLE_OK; + CURLcode result = CURLE_OK; #ifdef ENABLE_IPV6 if(conn->bits.ipv6_ip && @@ -1207,19 +1176,19 @@ static CURLcode verifyhost(struct connectdata *conn, infof(data, "\t subjectAltName does not match %s\n", conn->host.dispname); failf(data, "SSL: no alternative certificate subject name matches " "target host name '%s'", conn->host.dispname); - res = CURLE_PEER_FAILED_VERIFICATION; + result = CURLE_PEER_FAILED_VERIFICATION; } 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 */ unsigned char *nulstr = (unsigned char *)""; unsigned char *peer_CN = nulstr; - X509_NAME *name = X509_get_subject_name(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; @@ -1229,7 +1198,8 @@ static CURLcode verifyhost(struct connectdata *conn, UTF8 etc. */ if(i>=0) { - ASN1_STRING *tmp = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name,i)); + ASN1_STRING *tmp = + X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, i)); /* In OpenSSL 0.9.7d and earlier, ASN1_STRING_to_UTF8 fails if the input is already UTF-8 encoded. We check for this case and copy the raw @@ -1254,7 +1224,7 @@ static CURLcode verifyhost(struct connectdata *conn, /* there was a terminating zero before the end of string, this cannot match and we return failure! */ failf(data, "SSL: illegal cert name field"); - res = CURLE_PEER_FAILED_VERIFICATION; + result = CURLE_PEER_FAILED_VERIFICATION; } } } @@ -1271,18 +1241,18 @@ static CURLcode verifyhost(struct connectdata *conn, } } - if(res) + if(result) /* error already detected, pass through */ ; else if(!peer_CN) { failf(data, "SSL: unable to obtain common name from peer certificate"); - res = CURLE_PEER_FAILED_VERIFICATION; + result = CURLE_PEER_FAILED_VERIFICATION; } else if(!Curl_cert_hostcheck((const char *)peer_CN, conn->host.name)) { failf(data, "SSL: certificate subject name '%s' does not match " "target host name '%s'", peer_CN, conn->host.dispname); - res = CURLE_PEER_FAILED_VERIFICATION; + result = CURLE_PEER_FAILED_VERIFICATION; } else { infof(data, "\t common name: %s (matched)\n", peer_CN); @@ -1290,9 +1260,138 @@ static CURLcode verifyhost(struct connectdata *conn, if(peer_CN) OPENSSL_free(peer_CN); } - return res; + + return result; +} + +#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \ + !defined(OPENSSL_IS_BORINGSSL) +static CURLcode verifystatus(struct connectdata *conn, + struct ssl_connect_data *connssl) +{ + int i, ocsp_status; + const unsigned char *p; + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + + OCSP_RESPONSE *rsp = NULL; + OCSP_BASICRESP *br = NULL; + X509_STORE *st = NULL; + STACK_OF(X509) *ch = NULL; + + long len = SSL_get_tlsext_status_ocsp_resp(connssl->handle, &p); + + if(!p) { + failf(data, "No OCSP response received"); + result = CURLE_SSL_INVALIDCERTSTATUS; + goto end; + } + + rsp = d2i_OCSP_RESPONSE(NULL, &p, len); + if(!rsp) { + failf(data, "Invalid OCSP response"); + result = CURLE_SSL_INVALIDCERTSTATUS; + goto end; + } + + ocsp_status = OCSP_response_status(rsp); + if(ocsp_status != OCSP_RESPONSE_STATUS_SUCCESSFUL) { + failf(data, "Invalid OCSP response status: %s (%d)", + OCSP_response_status_str(ocsp_status), ocsp_status); + result = CURLE_SSL_INVALIDCERTSTATUS; + goto end; + } + + br = OCSP_response_get1_basic(rsp); + if(!br) { + failf(data, "Invalid OCSP response"); + result = CURLE_SSL_INVALIDCERTSTATUS; + goto end; + } + + ch = SSL_get_peer_cert_chain(connssl->handle); + st = SSL_CTX_get_cert_store(connssl->ctx); + +#if ((OPENSSL_VERSION_NUMBER <= 0x1000201fL) /* Fixed after 1.0.2a */ || \ + defined(LIBRESSL_VERSION_NUMBER)) + /* The authorized responder cert in the OCSP response MUST be signed by the + peer cert's issuer (see RFC6960 section 4.2.2.2). If that's a root cert, + no problem, but if it's an intermediate cert OpenSSL has a bug where it + expects this issuer to be present in the chain embedded in the OCSP + response. So we add it if necessary. */ + + /* First make sure the peer cert chain includes both a peer and an issuer, + and the OCSP response contains a responder cert. */ + if(sk_X509_num(ch) >= 2 && sk_X509_num(br->certs) >= 1) { + X509 *responder = sk_X509_value(br->certs, sk_X509_num(br->certs) - 1); + + /* Find issuer of responder cert and add it to the OCSP response chain */ + for(i = 0; i < sk_X509_num(ch); i++) { + X509 *issuer = sk_X509_value(ch, i); + if(X509_check_issued(issuer, responder) == X509_V_OK) { + if(!OCSP_basic_add1_cert(br, issuer)) { + failf(data, "Could not add issuer cert to OCSP response"); + result = CURLE_SSL_INVALIDCERTSTATUS; + goto end; + } + } + } + } +#endif + + if(OCSP_basic_verify(br, ch, st, 0) <= 0) { + failf(data, "OCSP response verification failed"); + result = CURLE_SSL_INVALIDCERTSTATUS; + goto end; + } + + for(i = 0; i < OCSP_resp_count(br); i++) { + int cert_status, crl_reason; + OCSP_SINGLERESP *single = NULL; + + ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd; + + if(!(single = OCSP_resp_get0(br, i))) + continue; + + cert_status = OCSP_single_get0_status(single, &crl_reason, &rev, + &thisupd, &nextupd); + + if(!OCSP_check_validity(thisupd, nextupd, 300L, -1L)) { + failf(data, "OCSP response has expired"); + result = CURLE_SSL_INVALIDCERTSTATUS; + goto end; + } + + infof(data, "SSL certificate status: %s (%d)\n", + OCSP_cert_status_str(cert_status), cert_status); + + switch(cert_status) { + case V_OCSP_CERTSTATUS_GOOD: + break; + + case V_OCSP_CERTSTATUS_REVOKED: + result = CURLE_SSL_INVALIDCERTSTATUS; + + failf(data, "SSL certificate revocation reason: %s (%d)", + OCSP_crl_reason_str(crl_reason), crl_reason); + goto end; + + case V_OCSP_CERTSTATUS_UNKNOWN: + result = CURLE_SSL_INVALIDCERTSTATUS; + goto end; + } + } + +end: + if(br) OCSP_BASICRESP_free(br); + OCSP_RESPONSE_free(rsp); + + return result; } -#endif /* USE_SSLEAY */ +#endif + +#endif /* USE_OPENSSL */ /* The SSL_CTRL_SET_MSG_CALLBACK doesn't exist in ancient OpenSSL versions and thus this cannot be done there. */ @@ -1300,6 +1399,7 @@ static CURLcode verifyhost(struct connectdata *conn, static const char *ssl_msg_type(int ssl_ver, int msg) { +#ifdef SSL2_VERSION_MAJOR if(ssl_ver == SSL2_VERSION_MAJOR) { switch (msg) { case SSL2_MT_ERROR: @@ -1322,7 +1422,9 @@ static const char *ssl_msg_type(int ssl_ver, int msg) return "Client CERT"; } } - else if(ssl_ver == SSL3_VERSION_MAJOR) { + else +#endif + if(ssl_ver == SSL3_VERSION_MAJOR) { switch (msg) { case SSL3_MT_HELLO_REQUEST: return "Hello request"; @@ -1330,8 +1432,12 @@ static const char *ssl_msg_type(int ssl_ver, int msg) return "Client hello"; case SSL3_MT_SERVER_HELLO: return "Server hello"; +#ifdef SSL3_MT_NEWSESSION_TICKET + case SSL3_MT_NEWSESSION_TICKET: + return "Newsession Ticket"; +#endif case SSL3_MT_CERTIFICATE: - return "CERT"; + return "Certificate"; case SSL3_MT_SERVER_KEY_EXCHANGE: return "Server key exchange"; case SSL3_MT_CLIENT_KEY_EXCHANGE: @@ -1344,6 +1450,10 @@ static const char *ssl_msg_type(int ssl_ver, int msg) return "CERT verify"; case SSL3_MT_FINISHED: return "Finished"; +#ifdef SSL3_MT_CERTIFICATE_STATUS + case SSL3_MT_CERTIFICATE_STATUS: + return "Certificate Status"; +#endif } } return "Unknown"; @@ -1351,12 +1461,22 @@ static const char *ssl_msg_type(int ssl_ver, int msg) static const char *tls_rt_type(int type) { - return ( - type == SSL3_RT_CHANGE_CIPHER_SPEC ? "TLS change cipher, " : - type == SSL3_RT_ALERT ? "TLS alert, " : - type == SSL3_RT_HANDSHAKE ? "TLS handshake, " : - type == SSL3_RT_APPLICATION_DATA ? "TLS app data, " : - "TLS Unknown, "); + switch(type) { +#ifdef SSL3_RT_HEADER + case SSL3_RT_HEADER: + return "TLS header"; +#endif + case SSL3_RT_CHANGE_CIPHER_SPEC: + return "TLS change cipher"; + case SSL3_RT_ALERT: + return "TLS alert"; + case SSL3_RT_HANDSHAKE: + return "TLS handshake"; + case SSL3_RT_APPLICATION_DATA: + return "TLS app data"; + default: + return "TLS Unknown"; + } } @@ -1364,38 +1484,77 @@ static const char *tls_rt_type(int type) * Our callback from the SSL/TLS layers. */ static void ssl_tls_trace(int direction, int ssl_ver, int content_type, - const void *buf, size_t len, const SSL *ssl, - struct connectdata *conn) + const void *buf, size_t len, SSL *ssl, + void *userp) { struct SessionHandle *data; const char *msg_name, *tls_rt_name; char ssl_buf[1024]; - int ver, msg_type, txt_len; + char unknown[32]; + int msg_type, txt_len; + const char *verstr = NULL; + struct connectdata *conn = userp; if(!conn || !conn->data || !conn->data->set.fdebug || (direction != 0 && direction != 1)) return; data = conn->data; - ssl_ver >>= 8; - ver = (ssl_ver == SSL2_VERSION_MAJOR ? '2' : - ssl_ver == SSL3_VERSION_MAJOR ? '3' : '?'); - /* SSLv2 doesn't seem to have TLS record-type headers, so OpenSSL - * always pass-up content-type as 0. But the interesting message-type - * is at 'buf[0]'. - */ - if(ssl_ver == SSL3_VERSION_MAJOR && content_type != 0) - tls_rt_name = tls_rt_type(content_type); - else - tls_rt_name = ""; + switch(ssl_ver) { +#ifdef SSL2_VERSION /* removed in recent versions */ + case SSL2_VERSION: + verstr = "SSLv2"; + break; +#endif +#ifdef SSL3_VERSION + case SSL3_VERSION: + verstr = "SSLv3"; + break; +#endif + case TLS1_VERSION: + verstr = "TLSv1.0"; + break; +#ifdef TLS1_1_VERSION + case TLS1_1_VERSION: + verstr = "TLSv1.1"; + break; +#endif +#ifdef TLS1_2_VERSION + case TLS1_2_VERSION: + verstr = "TLSv1.2"; + break; +#endif + case 0: + break; + default: + snprintf(unknown, sizeof(unknown), "(%x)", ssl_ver); + verstr = unknown; + break; + } + + if(ssl_ver) { + /* the info given when the version is zero is not that useful for us */ + + ssl_ver >>= 8; /* check the upper 8 bits only below */ - msg_type = *(char*)buf; - msg_name = ssl_msg_type(ssl_ver, msg_type); + /* SSLv2 doesn't seem to have TLS record-type headers, so OpenSSL + * always pass-up content-type as 0. But the interesting message-type + * is at 'buf[0]'. + */ + if(ssl_ver == SSL3_VERSION_MAJOR && content_type) + tls_rt_name = tls_rt_type(content_type); + else + tls_rt_name = ""; - txt_len = snprintf(ssl_buf, sizeof(ssl_buf), "SSLv%c, %s%s (%d):\n", - ver, tls_rt_name, msg_name, msg_type); - Curl_debug(data, CURLINFO_TEXT, ssl_buf, (size_t)txt_len, NULL); + msg_type = *(char*)buf; + msg_name = ssl_msg_type(ssl_ver, msg_type); + + txt_len = snprintf(ssl_buf, sizeof(ssl_buf), "%s (%s), %s, %s (%d):\n", + verstr, direction?"OUT":"IN", + tls_rt_name, msg_name, msg_type); + Curl_debug(data, CURLINFO_TEXT, ssl_buf, (size_t)txt_len, NULL); + } Curl_debug(data, (direction == 1) ? CURLINFO_SSL_DATA_OUT : CURLINFO_SSL_DATA_IN, (char *)buf, len, NULL); @@ -1403,7 +1562,7 @@ static void ssl_tls_trace(int direction, int ssl_ver, int content_type, } #endif -#ifdef USE_SSLEAY +#ifdef USE_OPENSSL /* ====================================================== */ #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME @@ -1412,26 +1571,44 @@ static void ssl_tls_trace(int direction, int ssl_ver, int content_type, # define use_sni(x) Curl_nop_stmt #endif -#ifdef USE_NGHTTP2 - +/* Check for OpenSSL 1.0.2 which has ALPN support. */ #undef HAS_ALPN -#if defined(HAVE_SSL_CTX_SET_ALPN_PROTOS) && \ - defined(HAVE_SSL_CTX_SET_ALPN_SELECT_CB) +#if OPENSSL_VERSION_NUMBER >= 0x10002000L \ + && !defined(OPENSSL_NO_TLSEXT) # define HAS_ALPN 1 #endif -#if !defined(HAVE_SSL_CTX_SET_NEXT_PROTO_SELECT_CB) || \ - defined(OPENSSL_NO_NEXTPROTONEG) -# if !defined(HAS_ALPN) -# error http2 builds require OpenSSL with NPN or ALPN support -# endif +/* Check for OpenSSL 1.0.1 which has NPN support. */ +#undef HAS_NPN +#if OPENSSL_VERSION_NUMBER >= 0x10001000L \ + && !defined(OPENSSL_NO_TLSEXT) \ + && !defined(OPENSSL_NO_NEXTPROTONEG) +# define HAS_NPN 1 #endif +#ifdef HAS_NPN /* * in is a list of lenght prefixed strings. this function has to select * the protocol we want to use from the list and write its string into out. */ + +static int +select_next_protocol(unsigned char **out, unsigned char *outlen, + const unsigned char *in, unsigned int inlen, + const char *key, unsigned int keylen) +{ + unsigned int i; + for(i = 0; i + keylen <= inlen; i += in[i] + 1) { + if(memcmp(&in[i + 1], key, keylen) == 0) { + *out = (unsigned char *) &in[i + 1]; + *outlen = in[i]; + return 0; + } + } + return -1; +} + static int select_next_proto_cb(SSL *ssl, unsigned char **out, unsigned char *outlen, @@ -1439,37 +1616,43 @@ select_next_proto_cb(SSL *ssl, void *arg) { struct connectdata *conn = (struct connectdata*) arg; - int retval = nghttp2_select_next_protocol(out, outlen, in, inlen); + (void)ssl; - if(retval == 1) { +#ifdef USE_NGHTTP2 + if(conn->data->set.httpversion == CURL_HTTP_VERSION_2_0 && + !select_next_protocol(out, outlen, in, inlen, NGHTTP2_PROTO_VERSION_ID, + NGHTTP2_PROTO_VERSION_ID_LEN)) { infof(conn->data, "NPN, negotiated HTTP2 (%s)\n", NGHTTP2_PROTO_VERSION_ID); - conn->negnpn = NPN_HTTP2; + conn->negnpn = CURL_HTTP_VERSION_2_0; + return SSL_TLSEXT_ERR_OK; } - else if(retval == 0) { +#endif + + if(!select_next_protocol(out, outlen, in, inlen, ALPN_HTTP_1_1, + ALPN_HTTP_1_1_LENGTH)) { infof(conn->data, "NPN, negotiated HTTP1.1\n"); - conn->negnpn = NPN_HTTP1_1; - } - else { - infof(conn->data, "NPN, no overlap, use HTTP1.1\n", - NGHTTP2_PROTO_VERSION_ID); - *out = (unsigned char*)"http/1.1"; - *outlen = sizeof("http/1.1") - 1; - conn->negnpn = NPN_HTTP1_1; + conn->negnpn = CURL_HTTP_VERSION_1_1; + return SSL_TLSEXT_ERR_OK; } + infof(conn->data, "NPN, no overlap, use HTTP1.1\n"); + *out = (unsigned char *)ALPN_HTTP_1_1; + *outlen = ALPN_HTTP_1_1_LENGTH; + conn->negnpn = CURL_HTTP_VERSION_1_1; + return SSL_TLSEXT_ERR_OK; } -#endif +#endif /* HAS_NPN */ static const char * -get_ssl_version_txt(SSL_SESSION *session) +get_ssl_version_txt(SSL *ssl) { - if(NULL == session) + if(!ssl) return ""; - switch(session->ssl_version) { + switch(SSL_version(ssl)) { #if OPENSSL_VERSION_NUMBER >= 0x1000100FL case TLS1_2_VERSION: return "TLSv1.2"; @@ -1486,17 +1669,14 @@ get_ssl_version_txt(SSL_SESSION *session) return "unknown"; } - -static CURLcode -ossl_connect_step1(struct connectdata *conn, - int sockindex) +static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) { - CURLcode retcode = CURLE_OK; + CURLcode result = CURLE_OK; char *ciphers; struct SessionHandle *data = conn->data; - SSL_METHOD_QUAL SSL_METHOD *req_method=NULL; - void *ssl_sessionid=NULL; - X509_LOOKUP *lookup=NULL; + SSL_METHOD_QUAL SSL_METHOD *req_method = NULL; + void *ssl_sessionid = NULL; + X509_LOOKUP *lookup = NULL; curl_socket_t sockfd = conn->sock[sockindex]; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; long ctx_options; @@ -1508,9 +1688,6 @@ ossl_connect_step1(struct connectdata *conn, struct in_addr addr; #endif #endif -#ifdef HAS_ALPN - unsigned char protocols[128]; -#endif DEBUGASSERT(ssl_connect_1 == connssl->connecting_state); @@ -1529,7 +1706,12 @@ ossl_connect_step1(struct connectdata *conn, case CURL_SSLVERSION_TLSv1_1: case CURL_SSLVERSION_TLSv1_2: /* it will be handled later with the context options */ +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && \ + !defined(LIBRESSL_VERSION_NUMBER) && !defined(OPENSSL_IS_BORINGSSL) + req_method = TLS_client_method(); +#else req_method = SSLv23_client_method(); +#endif use_sni(TRUE); break; case CURL_SSLVERSION_SSLv2: @@ -1546,6 +1728,10 @@ ossl_connect_step1(struct connectdata *conn, break; #endif case CURL_SSLVERSION_SSLv3: +#ifdef OPENSSL_NO_SSL3_METHOD + failf(data, "OpenSSL was built without SSLv3 support"); + return CURLE_NOT_BUILT_IN; +#else #ifdef USE_TLS_SRP if(data->set.ssl.authtype == CURL_TLSAUTH_SRP) return CURLE_SSL_CONNECT_ERROR; @@ -1553,6 +1739,7 @@ ossl_connect_step1(struct connectdata *conn, req_method = SSLv3_client_method(); use_sni(FALSE); break; +#endif } if(connssl->ctx) @@ -1571,16 +1758,9 @@ ossl_connect_step1(struct connectdata *conn, #ifdef SSL_CTRL_SET_MSG_CALLBACK if(data->set.fdebug && data->set.verbose) { - /* the SSL trace callback is only used for verbose logging so we only - inform about failures of setting it */ - if(!SSL_CTX_callback_ctrl(connssl->ctx, SSL_CTRL_SET_MSG_CALLBACK, - (void (*)(void))ssl_tls_trace)) { - infof(data, "SSL: couldn't set callback!\n"); - } - else if(!SSL_CTX_ctrl(connssl->ctx, SSL_CTRL_SET_MSG_CALLBACK_ARG, 0, - conn)) { - infof(data, "SSL: couldn't set callback argument!\n"); - } + /* 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); } #endif @@ -1593,7 +1773,7 @@ ossl_connect_step1(struct connectdata *conn, The "-no_ticket" option was introduced in Openssl0.9.8j. It's a flag to disable "rfc4507bis session ticket support". rfc4507bis was later turned - into the proper RFC5077 it seems: http://tools.ietf.org/html/rfc5077 + into the proper RFC5077 it seems: https://tools.ietf.org/html/rfc5077 The enabled extension concerns the session management. I wonder how often libcurl stops a connection and then resumes a TLS session. also, sending @@ -1613,7 +1793,7 @@ ossl_connect_step1(struct connectdata *conn, this option regardless of OpenSSL version and SSL_OP_ALL definition. OpenSSL added a work-around for a SSL 3.0/TLS 1.0 CBC vulnerability - (http://www.openssl.org/~bodo/tls-cbc.txt). In 0.9.6e they added a bit to + (https://www.openssl.org/~bodo/tls-cbc.txt). In 0.9.6e they added a bit to SSL_OP_ALL that _disables_ that work-around despite the fact that SSL_OP_ALL is documented to do "rather harmless" workarounds. In order to keep the secure work-around, the SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS bit @@ -1643,17 +1823,12 @@ ossl_connect_step1(struct connectdata *conn, #endif switch(data->set.ssl.version) { - case CURL_SSLVERSION_DEFAULT: - ctx_options |= SSL_OP_NO_SSLv2; + case CURL_SSLVERSION_SSLv3: #ifdef USE_TLS_SRP if(data->set.ssl.authtype == CURL_TLSAUTH_SRP) { infof(data, "Set version TLSv1.x for SRP authorisation\n"); - ctx_options |= SSL_OP_NO_SSLv3; } #endif - break; - - case CURL_SSLVERSION_SSLv3: ctx_options |= SSL_OP_NO_SSLv2; ctx_options |= SSL_OP_NO_TLSv1; #if OPENSSL_VERSION_NUMBER >= 0x1000100FL @@ -1662,6 +1837,7 @@ ossl_connect_step1(struct connectdata *conn, #endif break; + case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: ctx_options |= SSL_OP_NO_SSLv2; ctx_options |= SSL_OP_NO_SSLv3; @@ -1710,33 +1886,36 @@ ossl_connect_step1(struct connectdata *conn, SSL_CTX_set_options(connssl->ctx, ctx_options); -#ifdef USE_NGHTTP2 - if(data->set.httpversion == CURL_HTTP_VERSION_2_0) { - if(data->set.ssl_enable_npn) { - SSL_CTX_set_next_proto_select_cb(connssl->ctx, select_next_proto_cb, - conn); - } +#ifdef HAS_NPN + if(data->set.ssl_enable_npn) + SSL_CTX_set_next_proto_select_cb(connssl->ctx, select_next_proto_cb, conn); +#endif #ifdef HAS_ALPN - if(data->set.ssl_enable_alpn) { - protocols[0] = NGHTTP2_PROTO_VERSION_ID_LEN; - memcpy(&protocols[1], NGHTTP2_PROTO_VERSION_ID, - NGHTTP2_PROTO_VERSION_ID_LEN); + if(data->set.ssl_enable_alpn) { + int cur = 0; + unsigned char protocols[128]; - protocols[NGHTTP2_PROTO_VERSION_ID_LEN+1] = ALPN_HTTP_1_1_LENGTH; - memcpy(&protocols[NGHTTP2_PROTO_VERSION_ID_LEN+2], ALPN_HTTP_1_1, - ALPN_HTTP_1_1_LENGTH); - - /* expects length prefixed preference ordered list of protocols in wire - * format - */ - SSL_CTX_set_alpn_protos(connssl->ctx, protocols, - NGHTTP2_PROTO_VERSION_ID_LEN + ALPN_HTTP_1_1_LENGTH + 2); +#ifdef USE_NGHTTP2 + if(data->set.httpversion == CURL_HTTP_VERSION_2_0) { + protocols[cur++] = NGHTTP2_PROTO_VERSION_ID_LEN; - infof(data, "ALPN, offering %s, %s\n", NGHTTP2_PROTO_VERSION_ID, - ALPN_HTTP_1_1); + memcpy(&protocols[cur], NGHTTP2_PROTO_VERSION_ID, + NGHTTP2_PROTO_VERSION_ID_LEN); + cur += NGHTTP2_PROTO_VERSION_ID_LEN; + infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID); } #endif + + protocols[cur++] = ALPN_HTTP_1_1_LENGTH; + memcpy(&protocols[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH); + cur += ALPN_HTTP_1_1_LENGTH; + infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1); + + /* expects length prefixed preference ordered list of protocols in wire + * format + */ + SSL_CTX_set_alpn_protos(connssl->ctx, protocols, cur); } #endif @@ -1759,6 +1938,7 @@ ossl_connect_step1(struct connectdata *conn, failf(data, "failed setting cipher list: %s", ciphers); return CURLE_SSL_CIPHER; } + infof(data, "Cipher selection: %s\n", ciphers); #ifdef USE_TLS_SRP if(data->set.ssl.authtype == CURL_TLSAUTH_SRP) { @@ -1768,7 +1948,7 @@ ossl_connect_step1(struct connectdata *conn, failf(data, "Unable to set SRP user name"); return CURLE_BAD_FUNCTION_ARGUMENT; } - if(!SSL_CTX_set_srp_password(connssl->ctx,data->set.ssl.password)) { + if(!SSL_CTX_set_srp_password(connssl->ctx, data->set.ssl.password)) { failf(data, "failed setting SRP password"); return CURLE_BAD_FUNCTION_ARGUMENT; } @@ -1790,7 +1970,7 @@ ossl_connect_step1(struct connectdata *conn, data->set.str[STRING_SSL_CAPATH])) { if(data->set.ssl.verifypeer) { /* Fail if we insist on successfully verifying the server. */ - failf(data,"error setting certificate verify locations:\n" + failf(data, "error setting certificate verify locations:\n" " CAfile: %s\n CApath: %s", data->set.str[STRING_SSL_CAFILE]? data->set.str[STRING_SSL_CAFILE]: "none", @@ -1824,9 +2004,9 @@ ossl_connect_step1(struct connectdata *conn, lookup=X509_STORE_add_lookup(SSL_CTX_get_cert_store(connssl->ctx), X509_LOOKUP_file()); if(!lookup || - (!X509_load_crl_file(lookup,data->set.str[STRING_SSL_CRLFILE], + (!X509_load_crl_file(lookup, data->set.str[STRING_SSL_CRLFILE], X509_FILETYPE_PEM)) ) { - failf(data,"error loading CRL file: %s", + failf(data, "error loading CRL file: %s", data->set.str[STRING_SSL_CRLFILE]); return CURLE_SSL_CRL_BADFILE; } @@ -1841,21 +2021,35 @@ ossl_connect_step1(struct connectdata *conn, data->set.str[STRING_SSL_CRLFILE]: "none"); } + /* Try building a chain using issuers in the trusted store first to avoid + problems with server-sent legacy intermediates. + Newer versions of OpenSSL do alternate chain checking by default which + gives us the same fix without as much of a performance hit (slight), so we + prefer that if available. + https://rt.openssl.org/Ticket/Display.html?id=3621&user=guest&pass=guest + */ +#if defined(X509_V_FLAG_TRUSTED_FIRST) && !defined(X509_V_FLAG_NO_ALT_CHAINS) + if(data->set.ssl.verifypeer) { + X509_STORE_set_flags(SSL_CTX_get_cert_store(connssl->ctx), + X509_V_FLAG_TRUSTED_FIRST); + } +#endif + /* SSL always tries to verify the peer, this only says whether it should * 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, data->set.ssl.verifypeer?SSL_VERIFY_PEER:SSL_VERIFY_NONE, - cert_verify_callback); + NULL); /* give application a chance to interfere with SSL set up. */ if(data->set.ssl.fsslctx) { - retcode = (*data->set.ssl.fsslctx)(data, connssl->ctx, - data->set.ssl.fsslctxp); - if(retcode) { - failf(data,"error signaled by ssl ctx callback"); - return retcode; + result = (*data->set.ssl.fsslctx)(data, connssl->ctx, + data->set.ssl.fsslctxp); + if(result) { + failf(data, "error signaled by ssl ctx callback"); + return result; } } @@ -1867,6 +2061,13 @@ ossl_connect_step1(struct connectdata *conn, failf(data, "SSL: couldn't create a context (handle)!"); return CURLE_OUT_OF_MEMORY; } + +#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \ + !defined(OPENSSL_IS_BORINGSSL) + if(data->set.ssl.verifystatus) + SSL_set_tlsext_status_type(connssl->handle, TLSEXT_STATUSTYPE_ocsp); +#endif + SSL_set_connect_state(connssl->handle); connssl->server_cert = 0x0; @@ -1887,7 +2088,7 @@ ossl_connect_step1(struct connectdata *conn, /* we got a session id, use it! */ if(!SSL_set_session(connssl->handle, ssl_sessionid)) { failf(data, "SSL: SSL_set_session failed: %s", - ERR_error_string(ERR_get_error(),NULL)); + ERR_error_string(ERR_get_error(), NULL)); return CURLE_SSL_CONNECT_ERROR; } /* Informational message */ @@ -1897,16 +2098,16 @@ ossl_connect_step1(struct connectdata *conn, /* pass the raw socket into the SSL layers */ if(!SSL_set_fd(connssl->handle, (int)sockfd)) { failf(data, "SSL: SSL_set_fd failed: %s", - ERR_error_string(ERR_get_error(),NULL)); + ERR_error_string(ERR_get_error(), NULL)); return CURLE_SSL_CONNECT_ERROR; } connssl->connecting_state = ssl_connect_2; + return CURLE_OK; } -static CURLcode -ossl_connect_step2(struct connectdata *conn, int sockindex) +static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex) { struct SessionHandle *data = conn->data; int err; @@ -1936,10 +2137,9 @@ ossl_connect_step2(struct connectdata *conn, int sockindex) else { /* untreated error */ unsigned long errdetail; - char error_buffer[256]; /* OpenSSL documents that this must be at least - 256 bytes long. */ - CURLcode rc; - const char *cert_problem = NULL; + char error_buffer[256]=""; /* OpenSSL documents that this must be at + least 256 bytes long. */ + CURLcode result; long lerr; connssl->connecting_state = ssl_connect_2; /* the connection failed, @@ -1962,7 +2162,7 @@ ossl_connect_step2(struct connectdata *conn, int sockindex) SSL routines: SSL3_GET_SERVER_CERTIFICATE: certificate verify failed */ - rc = CURLE_SSL_CACERT; + result = CURLE_SSL_CACERT; lerr = SSL_get_verify_result(connssl->handle); if(lerr != X509_V_OK) { @@ -1971,12 +2171,13 @@ ossl_connect_step2(struct connectdata *conn, int sockindex) X509_verify_cert_error_string(lerr)); } else - cert_problem = "SSL certificate problem, verify that the CA cert is" - " OK."; - + /* strcpy() is fine here as long as the string fits within + error_buffer */ + strcpy(error_buffer, + "SSL certificate problem, check your CA cert"); break; default: - rc = CURLE_SSL_CONNECT_ERROR; + result = CURLE_SSL_CONNECT_ERROR; SSL_strerror(errdetail, error_buffer, sizeof(error_buffer)); break; } @@ -1987,15 +2188,16 @@ ossl_connect_step2(struct connectdata *conn, int sockindex) * (RST connection etc.), OpenSSL gives no explanation whatsoever and * the SO_ERROR is also lost. */ - if(CURLE_SSL_CONNECT_ERROR == rc && errdetail == 0) { + if(CURLE_SSL_CONNECT_ERROR == result && errdetail == 0) { failf(data, "Unknown SSL protocol error in connection to %s:%ld ", conn->host.name, conn->remote_port); - return rc; + return result; } + /* Could be a CERT problem */ + failf(data, "%s", error_buffer); - failf(data, "%s%s", cert_problem ? cert_problem : "", error_buffer); - return rc; + return result; } } else { @@ -2003,9 +2205,9 @@ ossl_connect_step2(struct connectdata *conn, int sockindex) connssl->connecting_state = ssl_connect_3; /* Informational message */ - infof (data, "SSL connection using %s / %s\n", - get_ssl_version_txt(SSL_get_session(connssl->handle)), - SSL_get_cipher(connssl->handle)); + infof(data, "SSL connection using %s / %s\n", + get_ssl_version_txt(connssl->handle), + SSL_get_cipher(connssl->handle)); #ifdef HAS_ALPN /* Sets data and len to negotiated protocol, len is 0 if no protocol was @@ -2018,18 +2220,20 @@ ossl_connect_step2(struct connectdata *conn, int sockindex) if(len != 0) { infof(data, "ALPN, server accepted to use %.*s\n", len, neg_protocol); +#ifdef USE_NGHTTP2 if(len == NGHTTP2_PROTO_VERSION_ID_LEN && - memcmp(NGHTTP2_PROTO_VERSION_ID, neg_protocol, len) == 0) { - conn->negnpn = NPN_HTTP2; + !memcmp(NGHTTP2_PROTO_VERSION_ID, neg_protocol, len)) { + conn->negnpn = CURL_HTTP_VERSION_2_0; } - else if(len == ALPN_HTTP_1_1_LENGTH && memcmp(ALPN_HTTP_1_1, - neg_protocol, ALPN_HTTP_1_1_LENGTH) == 0) { - conn->negnpn = NPN_HTTP1_1; + else +#endif + if(len == ALPN_HTTP_1_1_LENGTH && + !memcmp(ALPN_HTTP_1_1, neg_protocol, ALPN_HTTP_1_1_LENGTH)) { + conn->negnpn = CURL_HTTP_VERSION_1_1; } } - else { + else infof(data, "ALPN, server did not agree to a protocol\n"); - } } #endif @@ -2082,7 +2286,7 @@ static void pubkey_show(struct SessionHandle *data, #define print_pubkey_BN(_type, _name, _num) \ do { \ - if(pubkey->pkey._type->_name != NULL) { \ + if(pubkey->pkey._type->_name) { \ int len = BN_num_bytes(pubkey->pkey._type->_name); \ if(len < CERTBUFFERSIZE) { \ BN_bn2bin(pubkey->pkey._type->_name, (unsigned char*)bufp); \ @@ -2123,7 +2327,7 @@ static int X509V3_ext(struct SessionHandle *data, X509_EXTENSION_get_critical(ext)?"(critical)":""); if(!X509V3_EXT_print(bio_out, ext, 0, 0)) - M_ASN1_OCTET_STRING_print(bio_out, ext->value); + ASN1_STRING_print(bio_out, (ASN1_STRING *)X509_EXTENSION_get_data(ext)); BIO_get_mem_ptr(bio_out, &biomem); @@ -2160,6 +2364,7 @@ static void X509_signature(struct SessionHandle *data, char buf[1024]; char *ptr = buf; int i; + for(i=0; i<sig->length; i++) ptr+=snprintf(ptr, sizeof(buf)-(ptr-buf), "%02x:", sig->data[i]); @@ -2182,7 +2387,6 @@ static void dumpcert(struct SessionHandle *data, X509 *x, int numcert) "Cert", biomem->data, biomem->length); BIO_free(bio_out); - } /* @@ -2196,6 +2400,7 @@ static CURLcode get_cert_chain(struct connectdata *conn, struct ssl_connect_data *connssl) { + CURLcode result; STACK_OF(X509) *sk; int i; char *bufp; @@ -2213,9 +2418,11 @@ static CURLcode get_cert_chain(struct connectdata *conn, } numcerts = sk_X509_num(sk); - if(Curl_ssl_init_certinfo(data, numcerts)) { + + result = Curl_ssl_init_certinfo(data, numcerts); + if(result) { free(bufp); - return CURLE_OUT_OF_MEMORY; + return result; } infof(data, "--- Certificate chain\n"); @@ -2250,28 +2457,22 @@ static CURLcode get_cert_chain(struct connectdata *conn, Curl_ssl_push_certinfo(data, i, "Version", bufp); /* hex */ num=X509_get_serialNumber(x); - if(num->length <= 4) { - value = ASN1_INTEGER_get(num); - infof(data," Serial Number: %ld (0x%lx)\n", value, value); - snprintf(bufp, CERTBUFFERSIZE, "%lx", value); - } - else { + { int left = CERTBUFFERSIZE; ptr = bufp; - *ptr++ = 0; - if(num->type == V_ASN1_NEG_INTEGER) + if(num->type == V_ASN1_NEG_INTEGER) { *ptr++='-'; + left--; + } - for(j=0; (j<num->length) && (left>=4); j++) { - /* TODO: length restrictions */ - snprintf(ptr, 3, "%02x%c",num->data[j], - ((j+1 == num->length)?'\n':':')); - ptr += 3; - left-=4; + for(j=0; (j<num->length) && (left>=3); j++) { + snprintf(ptr, left, "%02x", num->data[j]); + ptr += 2; + left -= 2; } if(num->length) - infof(data," Serial Number: %s\n", bufp); + infof(data, " Serial Number: %s\n", bufp); else bufp[0]=0; } @@ -2357,6 +2558,65 @@ static CURLcode get_cert_chain(struct connectdata *conn, } /* + * Heavily modified from: + * https://www.owasp.org/index.php/Certificate_and_Public_Key_Pinning#OpenSSL + */ +static CURLcode pkp_pin_peer_pubkey(X509* cert, const char *pinnedpubkey) +{ + /* Scratch */ + int len1 = 0, len2 = 0; + unsigned char *buff1 = NULL, *temp = NULL; + + /* Result is returned to caller */ + CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH; + + /* if a path wasn't specified, don't pin */ + if(!pinnedpubkey) + return CURLE_OK; + + if(!cert) + return result; + + do { + /* Begin Gyrations to get the subjectPublicKeyInfo */ + /* Thanks to Viktor Dukhovni on the OpenSSL mailing list */ + + /* https://groups.google.com/group/mailing.openssl.users/browse_thread + /thread/d61858dae102c6c7 */ + len1 = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), NULL); + if(len1 < 1) + break; /* failed */ + + /* https://www.openssl.org/docs/crypto/buffer.html */ + buff1 = temp = OPENSSL_malloc(len1); + if(!buff1) + break; /* failed */ + + /* https://www.openssl.org/docs/crypto/d2i_X509.html */ + len2 = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), &temp); + + /* + * These checks are verifying we got back the same values as when we + * sized the buffer. It's pretty weak since they should always be the + * same. But it gives us something to test. + */ + if((len1 != len2) || !temp || ((temp - buff1) != len1)) + break; /* failed */ + + /* End Gyrations */ + + /* The one good exit point */ + result = Curl_pin_peer_pubkey(pinnedpubkey, buff1, len1); + } while(0); + + /* https://www.openssl.org/docs/crypto/buffer.html */ + if(buff1) + OPENSSL_free(buff1); + + return result; +} + +/* * Get the server cert, verify it and show it etc, only call failf() if the * 'strict' argument is TRUE as otherwise all this is for informational * purposes only! @@ -2368,7 +2628,7 @@ static CURLcode servercert(struct connectdata *conn, struct ssl_connect_data *connssl, bool strict) { - CURLcode retcode = CURLE_OK; + CURLcode result = CURLE_OK; int rc; long lerr; ASN1_TIME *certdate; @@ -2376,6 +2636,7 @@ static CURLcode servercert(struct connectdata *conn, X509 *issuer; FILE *fp; char *buffer = data->state.buffer; + const char *ptr; if(data->set.ssl.certinfo) /* we've been asked to gather certificate info! */ @@ -2387,7 +2648,8 @@ static CURLcode servercert(struct connectdata *conn, failf(data, "SSL: couldn't get peer certificate!"); return CURLE_PEER_FAILED_VERIFICATION; } - infof (data, "Server certificate:\n"); + + infof(data, "Server certificate:\n"); rc = x509_name_oneline(X509_get_subject_name(connssl->server_cert), buffer, BUFSIZE); @@ -2402,11 +2664,11 @@ static CURLcode servercert(struct connectdata *conn, infof(data, "\t expire date: %s\n", buffer); if(data->set.ssl.verifyhost) { - retcode = verifyhost(conn, connssl->server_cert); - if(retcode) { + result = verifyhost(conn, connssl->server_cert); + if(result) { X509_free(connssl->server_cert); connssl->server_cert = NULL; - return retcode; + return result; } } @@ -2415,7 +2677,7 @@ static CURLcode servercert(struct connectdata *conn, if(rc) { if(strict) failf(data, "SSL: couldn't get X509-issuer name!"); - retcode = CURLE_SSL_CONNECT_ERROR; + result = CURLE_SSL_CONNECT_ERROR; } else { infof(data, "\t issuer: %s\n", buffer); @@ -2425,7 +2687,7 @@ static CURLcode servercert(struct connectdata *conn, /* e.g. match issuer name with provided issuer certificate */ if(data->set.str[STRING_SSL_ISSUERCERT]) { - fp=fopen(data->set.str[STRING_SSL_ISSUERCERT],"r"); + fp = fopen(data->set.str[STRING_SSL_ISSUERCERT], FOPEN_READTEXT); if(!fp) { if(strict) failf(data, "SSL: Unable to open issuer cert (%s)", @@ -2434,7 +2696,8 @@ static CURLcode servercert(struct connectdata *conn, connssl->server_cert = NULL; return CURLE_SSL_ISSUER_ERROR; } - issuer = PEM_read_X509(fp,NULL,ZERO_NULL,NULL); + + issuer = PEM_read_X509(fp, NULL, ZERO_NULL, NULL); if(!issuer) { if(strict) failf(data, "SSL: Unable to read issuer cert (%s)", @@ -2444,8 +2707,10 @@ static CURLcode servercert(struct connectdata *conn, fclose(fp); return CURLE_SSL_ISSUER_ERROR; } + fclose(fp); - if(X509_check_issued(issuer,connssl->server_cert) != X509_V_OK) { + + if(X509_check_issued(issuer, connssl->server_cert) != X509_V_OK) { if(strict) failf(data, "SSL: Certificate issuer check failed (%s)", data->set.str[STRING_SSL_ISSUERCERT]); @@ -2454,13 +2719,15 @@ static CURLcode servercert(struct connectdata *conn, connssl->server_cert = NULL; return CURLE_SSL_ISSUER_ERROR; } + infof(data, "\t SSL certificate issuer check ok (%s)\n", data->set.str[STRING_SSL_ISSUERCERT]); X509_free(issuer); } - lerr = data->set.ssl.certverifyresult= + lerr = data->set.ssl.certverifyresult = SSL_get_verify_result(connssl->handle); + if(data->set.ssl.certverifyresult != X509_V_OK) { if(data->set.ssl.verifypeer) { /* We probably never reach this, because SSL_connect() will fail @@ -2468,7 +2735,7 @@ static CURLcode servercert(struct connectdata *conn, if(strict) failf(data, "SSL certificate verify result: %s (%ld)", X509_verify_cert_error_string(lerr), lerr); - retcode = CURLE_PEER_FAILED_VERIFICATION; + result = CURLE_PEER_FAILED_VERIFICATION; } else infof(data, "\t SSL certificate verify result: %s (%ld)," @@ -2479,46 +2746,52 @@ static CURLcode servercert(struct connectdata *conn, infof(data, "\t SSL certificate verify ok.\n"); } +#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \ + !defined(OPENSSL_IS_BORINGSSL) + if(data->set.ssl.verifystatus) { + result = verifystatus(conn, connssl); + if(result) { + X509_free(connssl->server_cert); + connssl->server_cert = NULL; + return result; + } + } +#endif + + if(!strict) + /* when not strict, we don't bother about the verify cert problems */ + result = CURLE_OK; + + ptr = data->set.str[STRING_SSL_PINNEDPUBLICKEY]; + if(!result && ptr) { + result = pkp_pin_peer_pubkey(connssl->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; connssl->connecting_state = ssl_connect_done; - return retcode; + return result; } - -static CURLcode -ossl_connect_step3(struct connectdata *conn, - int sockindex) +static CURLcode ossl_connect_step3(struct connectdata *conn, int sockindex) { - CURLcode retcode = CURLE_OK; - void *old_ssl_sessionid=NULL; + CURLcode result = CURLE_OK; + void *old_ssl_sessionid = NULL; struct SessionHandle *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - int incache; + bool incache; SSL_SESSION *our_ssl_sessionid; DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); -#ifdef HAVE_SSL_GET1_SESSION our_ssl_sessionid = SSL_get1_session(connssl->handle); - /* SSL_get1_session() will increment the reference - count and the session will stay in memory until explicitly freed with - SSL_SESSION_free(3), regardless of its state. - This function was introduced in openssl 0.9.5a. */ -#else - our_ssl_sessionid = SSL_get_session(connssl->handle); - - /* if SSL_get1_session() is unavailable, use SSL_get_session(). - This is an inferior option because the session can be flushed - at any time by openssl. It is included only so curl compiles - under versions of openssl < 0.9.5a. - - WARNING: How curl behaves if it's session is flushed is - untested. - */ -#endif + /* SSL_get1_session() will increment the reference count and the session + will stay in memory until explicitly freed with SSL_SESSION_free(3), + regardless of its state. */ incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL)); if(incache) { @@ -2528,15 +2801,15 @@ ossl_connect_step3(struct connectdata *conn, incache = FALSE; } } + if(!incache) { - retcode = Curl_ssl_addsessionid(conn, our_ssl_sessionid, - 0 /* unknown size */); - if(retcode) { + result = Curl_ssl_addsessionid(conn, our_ssl_sessionid, + 0 /* unknown size */); + if(result) { failf(data, "failed to store ssl session"); - return retcode; + return result; } } -#ifdef HAVE_SSL_GET1_SESSION else { /* Session was incache, so refcount already incremented earlier. * Avoid further increments with each SSL_get1_session() call. @@ -2544,7 +2817,6 @@ ossl_connect_step3(struct connectdata *conn, */ SSL_SESSION_free(our_ssl_sessionid); } -#endif /* * We check certificates to authenticate the server; otherwise we risk @@ -2553,26 +2825,24 @@ ossl_connect_step3(struct connectdata *conn, * operations. */ - if(!data->set.ssl.verifypeer && !data->set.ssl.verifyhost) - (void)servercert(conn, connssl, FALSE); - else - retcode = servercert(conn, connssl, TRUE); + result = servercert(conn, connssl, + (data->set.ssl.verifypeer || data->set.ssl.verifyhost)); - if(CURLE_OK == retcode) + if(!result) connssl->connecting_state = ssl_connect_done; - return retcode; + + return result; } static Curl_recv ossl_recv; static Curl_send ossl_send; -static CURLcode -ossl_connect_common(struct connectdata *conn, - int sockindex, - bool nonblocking, - bool *done) +static CURLcode ossl_connect_common(struct connectdata *conn, + int sockindex, + bool nonblocking, + bool *done) { - CURLcode retcode; + CURLcode result; struct SessionHandle *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; curl_socket_t sockfd = conn->sock[sockindex]; @@ -2585,7 +2855,7 @@ ossl_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); @@ -2594,9 +2864,10 @@ ossl_connect_common(struct connectdata *conn, failf(data, "SSL connection timeout"); return CURLE_OPERATION_TIMEDOUT; } - retcode = ossl_connect_step1(conn, sockindex); - if(retcode) - return retcode; + + result = ossl_connect_step1(conn, sockindex); + if(result) + return result; } while(ssl_connect_2 == connssl->connecting_state || @@ -2613,8 +2884,8 @@ ossl_connect_common(struct connectdata *conn, } /* if ssl is expecting something, check if it's available. */ - if(connssl->connecting_state == ssl_connect_2_reading - || connssl->connecting_state == ssl_connect_2_writing) { + if(connssl->connecting_state == ssl_connect_2_reading || + connssl->connecting_state == ssl_connect_2_writing) { curl_socket_t writefd = ssl_connect_2_writing== connssl->connecting_state?sockfd:CURL_SOCKET_BAD; @@ -2647,23 +2918,22 @@ ossl_connect_common(struct connectdata *conn, * before step2 has completed while ensuring that a client using select() * or epoll() will always have a valid fdset to wait on. */ - retcode = ossl_connect_step2(conn, sockindex); - if(retcode || (nonblocking && - (ssl_connect_2 == connssl->connecting_state || - ssl_connect_2_reading == connssl->connecting_state || - ssl_connect_2_writing == connssl->connecting_state))) - return retcode; + result = ossl_connect_step2(conn, sockindex); + if(result || (nonblocking && + (ssl_connect_2 == connssl->connecting_state || + ssl_connect_2_reading == connssl->connecting_state || + ssl_connect_2_writing == connssl->connecting_state))) + return result; } /* repeat step2 until all transactions are done. */ - - if(ssl_connect_3==connssl->connecting_state) { - retcode = ossl_connect_step3(conn, sockindex); - if(retcode) - return retcode; + if(ssl_connect_3 == connssl->connecting_state) { + result = ossl_connect_step3(conn, sockindex); + if(result) + return result; } - if(ssl_connect_done==connssl->connecting_state) { + if(ssl_connect_done == connssl->connecting_state) { connssl->state = ssl_connection_complete; conn->recv[sockindex] = ossl_recv; conn->send[sockindex] = ossl_send; @@ -2678,32 +2948,28 @@ ossl_connect_common(struct connectdata *conn, return CURLE_OK; } -CURLcode -Curl_ossl_connect_nonblocking(struct connectdata *conn, - int sockindex, - bool *done) +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) +CURLcode Curl_ossl_connect(struct connectdata *conn, int sockindex) { - CURLcode retcode; + CURLcode result; bool done = FALSE; - retcode = ossl_connect_common(conn, sockindex, FALSE, &done); - if(retcode) - return retcode; + result = ossl_connect_common(conn, sockindex, FALSE, &done); + if(result) + return result; DEBUGASSERT(done); return CURLE_OK; } -bool Curl_ossl_data_pending(const struct connectdata *conn, - int connindex) +bool Curl_ossl_data_pending(const struct connectdata *conn, int connindex) { if(conn->ssl[connindex].handle) /* SSL is in use */ @@ -2798,7 +3064,7 @@ static ssize_t ossl_recv(struct connectdata *conn, /* connection data */ default: /* openssl/ssl.h for SSL_ERROR_SYSCALL says "look at error stack/return value/errno" */ - /* http://www.openssl.org/docs/crypto/ERR_get_error.html */ + /* https://www.openssl.org/docs/crypto/ERR_get_error.html */ sslerror = ERR_get_error(); if((nread < 0) || sslerror) { /* If the return code was negative or there actually is an error in the @@ -2821,8 +3087,11 @@ size_t Curl_ossl_version(char *buffer, size_t size) to OpenSSL in all other aspects */ return snprintf(buffer, size, "yassl/%s", YASSL_VERSION); #else /* YASSL_VERSION */ +#ifdef OPENSSL_IS_BORINGSSL + return snprintf(buffer, size, "BoringSSL"); +#else /* OPENSSL_IS_BORINGSSL */ -#if(SSLEAY_VERSION_NUMBER >= 0x905000) +#if(OPENSSL_VERSION_NUMBER >= 0x905000) { char sub[3]; unsigned long ssleay_value; @@ -2850,47 +3119,44 @@ size_t Curl_ossl_version(char *buffer, size_t size) } return snprintf(buffer, size, "%s/%lx.%lx.%lx%s", -#ifdef OPENSSL_IS_BORINGSSL - "BoringSSL" -#else #ifdef LIBRESSL_VERSION_NUMBER "LibreSSL" #else "OpenSSL" #endif -#endif , (ssleay_value>>28)&0xf, (ssleay_value>>20)&0xff, (ssleay_value>>12)&0xff, sub); } -#else /* SSLEAY_VERSION_NUMBER is less than 0.9.5 */ +#else /* OPENSSL_VERSION_NUMBER is less than 0.9.5 */ -#if(SSLEAY_VERSION_NUMBER >= 0x900000) +#if(OPENSSL_VERSION_NUMBER >= 0x900000) return snprintf(buffer, size, "OpenSSL/%lx.%lx.%lx", - (SSLEAY_VERSION_NUMBER>>28)&0xff, - (SSLEAY_VERSION_NUMBER>>20)&0xff, - (SSLEAY_VERSION_NUMBER>>12)&0xf); + (OPENSSL_VERSION_NUMBER>>28)&0xff, + (OPENSSL_VERSION_NUMBER>>20)&0xff, + (OPENSSL_VERSION_NUMBER>>12)&0xf); -#else /* (SSLEAY_VERSION_NUMBER >= 0x900000) */ +#else /* (OPENSSL_VERSION_NUMBER >= 0x900000) */ { char sub[2]; sub[1]='\0'; - if(SSLEAY_VERSION_NUMBER&0x0f) { - sub[0]=(SSLEAY_VERSION_NUMBER&0x0f) + 'a' -1; + if(OPENSSL_VERSION_NUMBER&0x0f) { + sub[0]=(OPENSSL_VERSION_NUMBER&0x0f) + 'a' -1; } else sub[0]='\0'; return snprintf(buffer, size, "SSL/%x.%x.%x%s", - (SSLEAY_VERSION_NUMBER>>12)&0xff, - (SSLEAY_VERSION_NUMBER>>8)&0xf, - (SSLEAY_VERSION_NUMBER>>4)&0xf, sub); + (OPENSSL_VERSION_NUMBER>>12)&0xff, + (OPENSSL_VERSION_NUMBER>>8)&0xf, + (OPENSSL_VERSION_NUMBER>>4)&0xf, sub); } -#endif /* (SSLEAY_VERSION_NUMBER >= 0x900000) */ -#endif /* SSLEAY_VERSION_NUMBER is less than 0.9.5 */ +#endif /* (OPENSSL_VERSION_NUMBER >= 0x900000) */ +#endif /* OPENSSL_VERSION_NUMBER is less than 0.9.5 */ +#endif /* OPENSSL_IS_BORINGSSL */ #endif /* YASSL_VERSION */ } @@ -2898,8 +3164,9 @@ size_t Curl_ossl_version(char *buffer, size_t size) int Curl_ossl_random(struct SessionHandle *data, unsigned char *entropy, size_t length) { - if(data) + if(data) { Curl_ossl_seed(data); /* Initiate the seed if not already done */ + } RAND_bytes(entropy, curlx_uztosi(length)); return 0; /* 0 as in no problem */ } @@ -2915,4 +3182,28 @@ void Curl_ossl_md5sum(unsigned char *tmp, /* input */ MD5_Update(&MD5pw, tmp, tmplen); MD5_Final(md5sum, &MD5pw); } -#endif /* USE_SSLEAY */ + +#ifndef OPENSSL_NO_SHA256 +void Curl_ossl_sha256sum(const unsigned char *tmp, /* input */ + size_t tmplen, + unsigned char *sha256sum /* output */, + size_t unused) +{ + SHA256_CTX SHA256pw; + (void)unused; + SHA256_Init(&SHA256pw); + SHA256_Update(&SHA256pw, tmp, tmplen); + SHA256_Final(sha256sum, &SHA256pw); +} +#endif + +bool Curl_ossl_cert_status_request(void) +{ +#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \ + !defined(OPENSSL_IS_BORINGSSL) + return TRUE; +#else + return FALSE; +#endif +} +#endif /* USE_OPENSSL */ diff --git a/Utilities/cmcurl/lib/vtls/openssl.h b/Utilities/cmcurl/lib/vtls/openssl.h index 1a55ffc..a1f347a 100644 --- a/Utilities/cmcurl/lib/vtls/openssl.h +++ b/Utilities/cmcurl/lib/vtls/openssl.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -24,7 +24,7 @@ #include "curl_setup.h" -#ifdef USE_SSLEAY +#ifdef USE_OPENSSL /* * This header should only be needed to get included by vtls.c and openssl.c */ @@ -41,7 +41,7 @@ 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) */ -int Curl_ossl_close_all(struct SessionHandle *data); +void Curl_ossl_close_all(struct SessionHandle *data); /* Sets an OpenSSL engine */ CURLcode Curl_ossl_set_engine(struct SessionHandle *data, const char *engine); @@ -72,9 +72,24 @@ 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); + +/* 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 provides these functions: */ -#define have_curlssl_md5sum 1 +/* this backend supports CURLOPT_CERTINFO */ +#define have_curlssl_certinfo 1 + +/* this backend suppots CURLOPT_SSL_CTX_* */ +#define have_curlssl_ssl_ctx 1 /* API setup for OpenSSL */ #define curlssl_init Curl_ossl_init @@ -93,9 +108,13 @@ void Curl_ossl_md5sum(unsigned char *tmp, /* input */ #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) -#define CURL_SSL_BACKEND CURLSSLBACKEND_OPENSSL +#ifndef 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" +#define DEFAULT_CIPHER_SELECTION \ + "ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH" -#endif /* USE_SSLEAY */ +#endif /* USE_OPENSSL */ #endif /* HEADER_CURL_SSLUSE_H */ diff --git a/Utilities/cmcurl/lib/vtls/polarssl.c b/Utilities/cmcurl/lib/vtls/polarssl.c index 5332b92..066c055 100644 --- a/Utilities/cmcurl/lib/vtls/polarssl.c +++ b/Utilities/cmcurl/lib/vtls/polarssl.c @@ -6,7 +6,7 @@ * \___|\___/|_| \_\_____| * * Copyright (C) 2010 - 2011, Hoi-Ho Chan, <hoiho.chan@gmail.com> - * Copyright (C) 2012 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2012 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -55,9 +55,7 @@ #include "select.h" #include "rawstr.h" #include "polarssl_threadlock.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> +#include "curl_printf.h" #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" @@ -120,11 +118,8 @@ static void polarssl_debug(void *context, int level, const char *line) #endif /* ALPN for http2? */ -#ifdef USE_NGHTTP2 -# undef HAS_ALPN -# ifdef POLARSSL_SSL_ALPN -# define HAS_ALPN -# endif +#ifdef POLARSSL_SSL_ALPN +# define HAS_ALPN #endif static Curl_recv polarssl_recv; @@ -287,24 +282,38 @@ polarssl_connect_step1(struct connectdata *conn, } switch(data->set.ssl.version) { + default: + case CURL_SSLVERSION_DEFAULT: + case CURL_SSLVERSION_TLSv1: + ssl_set_min_version(&connssl->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_MINOR_VERSION_0); + ssl_set_max_version(&connssl->ssl, SSL_MAJOR_VERSION_3, + SSL_MINOR_VERSION_0); infof(data, "PolarSSL: Forced min. SSL Version to be SSLv3\n"); break; case CURL_SSLVERSION_TLSv1_0: ssl_set_min_version(&connssl->ssl, SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_1); + ssl_set_max_version(&connssl->ssl, SSL_MAJOR_VERSION_3, + SSL_MINOR_VERSION_1); infof(data, "PolarSSL: Forced min. SSL Version to be TLS 1.0\n"); break; case CURL_SSLVERSION_TLSv1_1: ssl_set_min_version(&connssl->ssl, SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_2); + ssl_set_max_version(&connssl->ssl, SSL_MAJOR_VERSION_3, + SSL_MINOR_VERSION_2); infof(data, "PolarSSL: Forced min. SSL Version to be TLS 1.1\n"); break; case CURL_SSLVERSION_TLSv1_2: ssl_set_min_version(&connssl->ssl, SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_3); + ssl_set_max_version(&connssl->ssl, SSL_MAJOR_VERSION_3, + SSL_MINOR_VERSION_3); infof(data, "PolarSSL: Forced min. SSL Version to be TLS 1.2\n"); break; } @@ -345,15 +354,23 @@ polarssl_connect_step1(struct connectdata *conn, } #ifdef HAS_ALPN - if(data->set.httpversion == CURL_HTTP_VERSION_2_0) { - if(data->set.ssl_enable_alpn) { - static const char* protocols[] = { - NGHTTP2_PROTO_VERSION_ID, ALPN_HTTP_1_1, NULL - }; - ssl_set_alpn_protocols(&connssl->ssl, protocols); - infof(data, "ALPN, offering %s, %s\n", protocols[0], - protocols[1]); + if(data->set.ssl_enable_alpn) { + static const char* protocols[3]; + int cur = 0; + +#ifdef USE_NGHTTP2 + if(data->set.httpversion == CURL_HTTP_VERSION_2_0) { + protocols[cur++] = NGHTTP2_PROTO_VERSION_ID; + infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID); } +#endif + + protocols[cur++] = ALPN_HTTP_1_1; + infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1); + + protocols[cur] = NULL; + + ssl_set_alpn_protocols(&connssl->ssl, protocols); } #endif @@ -375,47 +392,37 @@ polarssl_connect_step2(struct connectdata *conn, struct ssl_connect_data* connssl = &conn->ssl[sockindex]; char buffer[1024]; -#ifdef HAS_ALPN - const char* next_protocol; -#endif - char errorbuf[128]; errorbuf[0] = 0; conn->recv[sockindex] = polarssl_recv; conn->send[sockindex] = polarssl_send; - for(;;) { - if(!(ret = ssl_handshake(&connssl->ssl))) - break; - else if(ret != POLARSSL_ERR_NET_WANT_READ && - ret != POLARSSL_ERR_NET_WANT_WRITE) { -#ifdef POLARSSL_ERROR_C - error_strerror(ret, errorbuf, sizeof(errorbuf)); -#endif /* POLARSSL_ERROR_C */ - failf(data, "ssl_handshake returned - PolarSSL: (-0x%04X) %s", - -ret, errorbuf); + ret = ssl_handshake(&connssl->ssl); - return CURLE_SSL_CONNECT_ERROR; - } - else { - if(ret == POLARSSL_ERR_NET_WANT_READ) { - connssl->connecting_state = ssl_connect_2_reading; - return CURLE_OK; - } - if(ret == POLARSSL_ERR_NET_WANT_WRITE) { - connssl->connecting_state = ssl_connect_2_writing; - return CURLE_OK; - } - failf(data, "SSL_connect failed with error %d.", ret); - return CURLE_SSL_CONNECT_ERROR; + switch(ret) { + case 0: + break; - } + case POLARSSL_ERR_NET_WANT_READ: + connssl->connecting_state = ssl_connect_2_reading; + return CURLE_OK; + + case POLARSSL_ERR_NET_WANT_WRITE: + connssl->connecting_state = ssl_connect_2_writing; + return CURLE_OK; + + default: +#ifdef POLARSSL_ERROR_C + error_strerror(ret, errorbuf, sizeof(errorbuf)); +#endif /* POLARSSL_ERROR_C */ + failf(data, "ssl_handshake returned - PolarSSL: (-0x%04X) %s", + -ret, errorbuf); + return CURLE_SSL_CONNECT_ERROR; } infof(data, "PolarSSL: Handshake complete, cipher is %s\n", - ssl_get_ciphersuite(&conn->ssl[sockindex].ssl) - ); + ssl_get_ciphersuite(&conn->ssl[sockindex].ssl) ); ret = ssl_get_verify_result(&conn->ssl[sockindex].ssl); @@ -448,22 +455,24 @@ polarssl_connect_step2(struct connectdata *conn, #ifdef HAS_ALPN if(data->set.ssl_enable_alpn) { - next_protocol = ssl_get_alpn_protocol(&connssl->ssl); + const char *next_protocol = ssl_get_alpn_protocol(&connssl->ssl); if(next_protocol != NULL) { infof(data, "ALPN, server accepted to use %s\n", next_protocol); - if(strncmp(next_protocol, NGHTTP2_PROTO_VERSION_ID, +#ifdef USE_NGHTTP2 + if(!strncmp(next_protocol, NGHTTP2_PROTO_VERSION_ID, NGHTTP2_PROTO_VERSION_ID_LEN)) { - conn->negnpn = NPN_HTTP2; + conn->negnpn = CURL_HTTP_VERSION_2_0; } - else if(strncmp(next_protocol, ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH)) { - conn->negnpn = NPN_HTTP1_1; + else +#endif + if(!strncmp(next_protocol, ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH)) { + conn->negnpn = CURL_HTTP_VERSION_1_1; } } - else { + else infof(data, "ALPN, server did not agree to a protocol\n"); - } } #endif @@ -477,12 +486,12 @@ static CURLcode polarssl_connect_step3(struct connectdata *conn, int sockindex) { - CURLcode retcode = CURLE_OK; + CURLcode result = CURLE_OK; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; struct SessionHandle *data = conn->data; void *old_ssl_sessionid = NULL; - ssl_session *our_ssl_sessionid = &conn->ssl[sockindex].ssn ; - int incache; + ssl_session *our_ssl_sessionid = &conn->ssl[sockindex].ssn; + bool incache; DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); @@ -495,23 +504,21 @@ polarssl_connect_step3(struct connectdata *conn, incache = FALSE; } } + if(!incache) { void *new_session = malloc(sizeof(ssl_session)); if(new_session) { - memcpy(new_session, our_ssl_sessionid, - sizeof(ssl_session)); + memcpy(new_session, our_ssl_sessionid, sizeof(ssl_session)); - retcode = Curl_ssl_addsessionid(conn, new_session, - sizeof(ssl_session)); - } - else { - retcode = CURLE_OUT_OF_MEMORY; + result = Curl_ssl_addsessionid(conn, new_session, sizeof(ssl_session)); } + else + result = CURLE_OUT_OF_MEMORY; - if(retcode) { + if(result) { failf(data, "failed to store ssl session"); - return retcode; + return result; } } @@ -540,11 +547,6 @@ static ssize_t polarssl_send(struct connectdata *conn, return ret; } -void Curl_polarssl_close_all(struct SessionHandle *data) -{ - (void)data; -} - void Curl_polarssl_close(struct connectdata *conn, int sockindex) { rsa_free(&conn->ssl[sockindex].rsa); @@ -585,11 +587,15 @@ void Curl_polarssl_session_free(void *ptr) free(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) { unsigned int version = version_get_number(); - return snprintf(buffer, size, "PolarSSL/%d.%d.%d", version>>24, - (version>>16)&0xff, (version>>8)&0xff); + return snprintf(buffer, size, "%s/%d.%d.%d", + version >= 0x01030A00?"mbedTLS":"PolarSSL", + version>>24, (version>>16)&0xff, (version>>8)&0xff); } static CURLcode @@ -598,7 +604,7 @@ polarssl_connect_common(struct connectdata *conn, bool nonblocking, bool *done) { - CURLcode retcode; + CURLcode result; struct SessionHandle *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; curl_socket_t sockfd = conn->sock[sockindex]; @@ -611,7 +617,7 @@ polarssl_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); @@ -620,9 +626,10 @@ polarssl_connect_common(struct connectdata *conn, failf(data, "SSL connection timeout"); return CURLE_OPERATION_TIMEDOUT; } - retcode = polarssl_connect_step1(conn, sockindex); - if(retcode) - return retcode; + + result = polarssl_connect_step1(conn, sockindex); + if(result) + return result; } while(ssl_connect_2 == connssl->connecting_state || @@ -639,8 +646,8 @@ polarssl_connect_common(struct connectdata *conn, } /* if ssl is expecting something, check if it's available. */ - if(connssl->connecting_state == ssl_connect_2_reading - || connssl->connecting_state == ssl_connect_2_writing) { + if(connssl->connecting_state == ssl_connect_2_reading || + connssl->connecting_state == ssl_connect_2_writing) { curl_socket_t writefd = ssl_connect_2_writing== connssl->connecting_state?sockfd:CURL_SOCKET_BAD; @@ -674,22 +681,22 @@ polarssl_connect_common(struct connectdata *conn, * ensuring that a client using select() or epoll() will always * have a valid fdset to wait on. */ - retcode = polarssl_connect_step2(conn, sockindex); - if(retcode || (nonblocking && - (ssl_connect_2 == connssl->connecting_state || - ssl_connect_2_reading == connssl->connecting_state || - ssl_connect_2_writing == connssl->connecting_state))) - return retcode; + result = polarssl_connect_step2(conn, sockindex); + if(result || (nonblocking && + (ssl_connect_2 == connssl->connecting_state || + ssl_connect_2_reading == connssl->connecting_state || + ssl_connect_2_writing == connssl->connecting_state))) + return result; } /* repeat step2 until all transactions are done. */ - if(ssl_connect_3==connssl->connecting_state) { - retcode = polarssl_connect_step3(conn, sockindex); - if(retcode) - return retcode; + if(ssl_connect_3 == connssl->connecting_state) { + result = polarssl_connect_step3(conn, sockindex); + if(result) + return result; } - if(ssl_connect_done==connssl->connecting_state) { + if(ssl_connect_done == connssl->connecting_state) { connssl->state = ssl_connection_complete; conn->recv[sockindex] = polarssl_recv; conn->send[sockindex] = polarssl_send; @@ -717,12 +724,12 @@ CURLcode Curl_polarssl_connect(struct connectdata *conn, int sockindex) { - CURLcode retcode; + CURLcode result; bool done = FALSE; - retcode = polarssl_connect_common(conn, sockindex, FALSE, &done); - if(retcode) - return retcode; + result = polarssl_connect_common(conn, sockindex, FALSE, &done); + if(result) + return result; DEBUGASSERT(done); diff --git a/Utilities/cmcurl/lib/vtls/polarssl.h b/Utilities/cmcurl/lib/vtls/polarssl.h index 9ab7e47..f980dbb 100644 --- a/Utilities/cmcurl/lib/vtls/polarssl.h +++ b/Utilities/cmcurl/lib/vtls/polarssl.h @@ -8,6 +8,7 @@ * \___|\___/|_| \_\_____| * * Copyright (C) 2010, Hoi-Ho Chan, <hoiho.chan@gmail.com> + * Copyright (C) 2012 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -36,10 +37,6 @@ CURLcode Curl_polarssl_connect_nonblocking(struct connectdata *conn, int sockindex, bool *done); -/* tell PolarSSL to close down all open information regarding connections (and - thus session ID caching etc) */ -void Curl_polarssl_close_all(struct SessionHandle *data); - /* close a SSL connection */ void Curl_polarssl_close(struct connectdata *conn, int sockindex); @@ -47,27 +44,32 @@ 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 + /* API setup for PolarSSL */ #define curlssl_init() polarssl_init() #define curlssl_cleanup() 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 Curl_polarssl_close_all +#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) (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_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) (x=x, -1) -#define curlssl_data_pending(x,y) (x=x, y=y, 0) -#define CURL_SSL_BACKEND CURLSSLBACKEND_POLARSSL +#define curlssl_check_cxn(x) ((void)x, -1) +#define curlssl_data_pending(x,y) ((void)x, (void)y, 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) (x=x, y=y, z=z, CURLE_NOT_BUILT_IN) +#define curlssl_random(x,y,z) ((void)x, (void)y, (void)z, CURLE_NOT_BUILT_IN) #endif /* USE_POLARSSL */ #endif /* HEADER_CURL_POLARSSL_H */ diff --git a/Utilities/cmcurl/lib/vtls/polarssl_threadlock.c b/Utilities/cmcurl/lib/vtls/polarssl_threadlock.c index ad18715..62abf43 100644 --- a/Utilities/cmcurl/lib/vtls/polarssl_threadlock.c +++ b/Utilities/cmcurl/lib/vtls/polarssl_threadlock.c @@ -36,10 +36,7 @@ #endif #include "polarssl_threadlock.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - +#include "curl_printf.h" #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" diff --git a/Utilities/cmcurl/lib/vtls/qssl.c b/Utilities/cmcurl/lib/vtls/qssl.c deleted file mode 100644 index 4c32053..0000000 --- a/Utilities/cmcurl/lib/vtls/qssl.c +++ /dev/null @@ -1,527 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. - * - * You may opt to use, copy, modify, merge, publish, distribute and/or sell - * copies of the Software, and permit persons to whom the Software is - * furnished to do so, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifdef USE_QSOSSL - -#include <qsossl.h> - -#ifdef HAVE_LIMITS_H -# include <limits.h> -#endif - -#include <curl/curl.h> -#include "urldata.h" -#include "sendf.h" -#include "qssl.h" -#include "vtls.h" -#include "connect.h" /* for the connect timeout */ -#include "select.h" -#include "x509asn1.h" -#include "curl_memory.h" -/* The last #include file should be: */ -#include "memdebug.h" - - -int Curl_qsossl_init(void) - -{ - /* Nothing to do here. We must have connection data to initialize ssl, so - * defer. - */ - - return 1; -} - - -void Curl_qsossl_cleanup(void) - -{ - /* Nothing to do. */ -} - - -static CURLcode Curl_qsossl_init_session(struct SessionHandle * data) - -{ - int rc; - char * certname; - SSLInit initstr; - SSLInitApp initappstr; - - /* Initialize the job for SSL according to the current parameters. - * QsoSSL offers two ways to do it: SSL_Init_Application() that uses an - * application identifier to select certificates in the main certificate - * store, and SSL_Init() that uses named keyring files and a password. - * It is not possible to have different keyrings for the CAs and the - * local certificate. We thus use the certificate name to identify the - * keyring if given, else the CA file name. - * If the key file name is given, it is taken as the password for the - * keyring in certificate file. - * We first try to SSL_Init_Application(), then SSL_Init() if it failed. - */ - - certname = data->set.str[STRING_CERT]; - - if(!certname) { - certname = data->set.str[STRING_SSL_CAFILE]; - - if(!certname) - return CURLE_OK; /* Use previous setup. */ - } - - memset((char *) &initappstr, 0, sizeof initappstr); - initappstr.applicationID = certname; - initappstr.applicationIDLen = strlen(certname); - initappstr.protocol = SSL_VERSION_CURRENT; /* TLSV1 compat. SSLV[23]. */ - initappstr.sessionType = SSL_REGISTERED_AS_CLIENT; - rc = SSL_Init_Application(&initappstr); - - if(rc == SSL_ERROR_NOT_REGISTERED) { - initstr.keyringFileName = certname; - initstr.keyringPassword = data->set.str[STRING_KEY]; - initstr.cipherSuiteList = NULL; /* Use default. */ - initstr.cipherSuiteListLen = 0; - rc = SSL_Init(&initstr); - } - - switch (rc) { - - case 0: /* No error. */ - break; - - case SSL_ERROR_IO: - failf(data, "SSL_Init() I/O error: %s", strerror(errno)); - return CURLE_SSL_CONNECT_ERROR; - - case SSL_ERROR_BAD_CIPHER_SUITE: - return CURLE_SSL_CIPHER; - - case SSL_ERROR_KEYPASSWORD_EXPIRED: - case SSL_ERROR_NOT_REGISTERED: - return CURLE_SSL_CONNECT_ERROR; - - case SSL_ERROR_NO_KEYRING: - return CURLE_SSL_CACERT; - - case SSL_ERROR_CERT_EXPIRED: - return CURLE_SSL_CERTPROBLEM; - - default: - failf(data, "SSL_Init(): %s", SSL_Strerror(rc, NULL)); - return CURLE_SSL_CONNECT_ERROR; - } - - return CURLE_OK; -} - - -static CURLcode Curl_qsossl_create(struct connectdata * conn, int sockindex) - -{ - SSLHandle * h; - struct ssl_connect_data * connssl = &conn->ssl[sockindex]; - - h = SSL_Create(conn->sock[sockindex], SSL_ENCRYPT); - - if(!h) { - failf(conn->data, "SSL_Create() I/O error: %s", strerror(errno)); - return CURLE_SSL_CONNECT_ERROR; - } - - connssl->handle = h; - return CURLE_OK; -} - - -static int Curl_qsossl_trap_cert(SSLHandle * h) - -{ - return 1; /* Accept certificate. */ -} - - -static CURLcode Curl_qsossl_handshake(struct connectdata * conn, int sockindex) - -{ - int rc; - struct SessionHandle * data = conn->data; - struct ssl_connect_data * connssl = &conn->ssl[sockindex]; - SSLHandle * h = connssl->handle; - long timeout_ms; - - h->exitPgm = data->set.ssl.verifypeer? NULL: Curl_qsossl_trap_cert; - - /* figure out how long time we should wait at maximum */ - timeout_ms = Curl_timeleft(data, NULL, TRUE); - - if(timeout_ms < 0) { - /* time-out, bail out, go home */ - failf(data, "Connection time-out"); - return CURLE_OPERATION_TIMEDOUT; - } - - /* SSL_Handshake() timeout resolution is second, so round up. */ - h->timeout = (timeout_ms + 1000 - 1) / 1000; - - /* Set-up protocol. */ - - switch (data->set.ssl.version) { - - default: - case CURL_SSLVERSION_DEFAULT: - h->protocol = SSL_VERSION_CURRENT; /* TLSV1 compat. SSLV[23]. */ - break; - - case CURL_SSLVERSION_TLSv1: - h->protocol = TLS_VERSION_1; - break; - - case CURL_SSLVERSION_SSLv2: - h->protocol = SSL_VERSION_2; - break; - - case CURL_SSLVERSION_SSLv3: - h->protocol = SSL_VERSION_3; - break; - - case CURL_SSLVERSION_TLSv1_0: - case CURL_SSLVERSION_TLSv1_1: - case CURL_SSLVERSION_TLSv1_2: - failf(data, "TLS minor version cannot be set"); - return CURLE_SSL_CONNECT_ERROR; - } - - h->peerCert = NULL; - h->peerCertLen = 0; - rc = SSL_Handshake(h, SSL_HANDSHAKE_AS_CLIENT); - - switch (rc) { - - case 0: /* No error. */ - break; - - case SSL_ERROR_BAD_CERTIFICATE: - case SSL_ERROR_BAD_CERT_SIG: - case SSL_ERROR_NOT_TRUSTED_ROOT: - return CURLE_PEER_FAILED_VERIFICATION; - - case SSL_ERROR_BAD_CIPHER_SUITE: - case SSL_ERROR_NO_CIPHERS: - return CURLE_SSL_CIPHER; - - case SSL_ERROR_CERTIFICATE_REJECTED: - case SSL_ERROR_CERT_EXPIRED: - case SSL_ERROR_NO_CERTIFICATE: - return CURLE_SSL_CERTPROBLEM; - - case SSL_ERROR_IO: - failf(data, "SSL_Handshake() I/O error: %s", strerror(errno)); - return CURLE_SSL_CONNECT_ERROR; - - default: - failf(data, "SSL_Handshake(): %s", SSL_Strerror(rc, NULL)); - return CURLE_SSL_CONNECT_ERROR; - } - - /* Verify host. */ - rc = Curl_verifyhost(conn, h->peerCert, h->peerCert + h->peerCertLen); - if(rc != CURLE_OK) - return rc; - - /* Gather certificate info. */ - if(data->set.ssl.certinfo) { - if(Curl_ssl_init_certinfo(data, 1)) - return CURLE_OUT_OF_MEMORY; - if(h->peerCert) { - rc = Curl_extract_certinfo(conn, 0, h->peerCert, - h->peerCert + h->peerCertLen); - if(rc != CURLE_OK) - return rc; - } - } - - return CURLE_OK; -} - - -static Curl_recv qsossl_recv; -static Curl_send qsossl_send; - -CURLcode Curl_qsossl_connect(struct connectdata * conn, int sockindex) - -{ - struct SessionHandle * data = conn->data; - struct ssl_connect_data * connssl = &conn->ssl[sockindex]; - int rc; - - rc = Curl_qsossl_init_session(data); - - if(rc == CURLE_OK) { - rc = Curl_qsossl_create(conn, sockindex); - - if(rc == CURLE_OK) { - rc = Curl_qsossl_handshake(conn, sockindex); - if(rc != CURLE_OK) - SSL_Destroy(connssl->handle); - } - } - - if(rc == CURLE_OK) { - conn->recv[sockindex] = qsossl_recv; - conn->send[sockindex] = qsossl_send; - connssl->state = ssl_connection_complete; - } - else { - connssl->handle = NULL; - connssl->use = FALSE; - connssl->state = ssl_connection_none; - } - - return rc; -} - - -static int Curl_qsossl_close_one(struct ssl_connect_data * conn, - struct SessionHandle * data) - -{ - int rc; - - if(!conn->handle) - return 0; - - rc = SSL_Destroy(conn->handle); - - if(rc) { - if(rc == SSL_ERROR_IO) { - failf(data, "SSL_Destroy() I/O error: %s", strerror(errno)); - return -1; - } - - /* An SSL error. */ - failf(data, "SSL_Destroy() returned error %s", SSL_Strerror(rc, NULL)); - return -1; - } - - conn->handle = NULL; - return 0; -} - - -void Curl_qsossl_close(struct connectdata *conn, int sockindex) - -{ - struct SessionHandle *data = conn->data; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - - if(connssl->use) - (void) Curl_qsossl_close_one(connssl, data); -} - - -int Curl_qsossl_close_all(struct SessionHandle * data) - -{ - /* Unimplemented. */ - (void) data; - return 0; -} - - -int Curl_qsossl_shutdown(struct connectdata * conn, int sockindex) - -{ - struct ssl_connect_data * connssl = &conn->ssl[sockindex]; - struct SessionHandle *data = conn->data; - ssize_t nread; - int what; - int rc; - char buf[120]; - - if(!connssl->handle) - return 0; - - if(data->set.ftp_ccc != CURLFTPSSL_CCC_ACTIVE) - return 0; - - if(Curl_qsossl_close_one(connssl, data)) - return -1; - - rc = 0; - - what = Curl_socket_ready(conn->sock[sockindex], - CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT); - - for(;;) { - if(what < 0) { - /* anything that gets here is fatally bad */ - failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); - rc = -1; - break; - } - - if(!what) { /* timeout */ - failf(data, "SSL shutdown timeout"); - break; - } - - /* Something to read, let's do it and hope that it is the close - notify alert from the server. No way to SSL_Read now, so use read(). */ - - nread = read(conn->sock[sockindex], buf, sizeof(buf)); - - if(nread < 0) { - failf(data, "read: %s", strerror(errno)); - rc = -1; - } - - if(nread <= 0) - break; - - what = Curl_socket_ready(conn->sock[sockindex], CURL_SOCKET_BAD, 0); - } - - return rc; -} - - -static ssize_t qsossl_send(struct connectdata * conn, int sockindex, - const void * mem, size_t len, CURLcode * curlcode) - -{ - /* SSL_Write() is said to return 'int' while write() and send() returns - 'size_t' */ - int rc; - - rc = SSL_Write(conn->ssl[sockindex].handle, (void *) mem, (int) len); - - if(rc < 0) { - switch(rc) { - - case SSL_ERROR_BAD_STATE: - /* The operation did not complete; the same SSL I/O function - should be called again later. This is basically an EWOULDBLOCK - equivalent. */ - *curlcode = CURLE_AGAIN; - return -1; - - case SSL_ERROR_IO: - switch (errno) { - case EWOULDBLOCK: - case EINTR: - *curlcode = CURLE_AGAIN; - return -1; - } - - failf(conn->data, "SSL_Write() I/O error: %s", strerror(errno)); - *curlcode = CURLE_SEND_ERROR; - return -1; - } - - /* An SSL error. */ - failf(conn->data, "SSL_Write() returned error %s", - SSL_Strerror(rc, NULL)); - *curlcode = CURLE_SEND_ERROR; - return -1; - } - - return (ssize_t) rc; /* number of bytes */ -} - - -static ssize_t qsossl_recv(struct connectdata * conn, int num, char * buf, - size_t buffersize, CURLcode * curlcode) - -{ - char error_buffer[120]; /* OpenSSL documents that this must be at - least 120 bytes long. */ - unsigned long sslerror; - int buffsize; - int nread; - - buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize; - nread = SSL_Read(conn->ssl[num].handle, buf, buffsize); - - if(nread < 0) { - /* failed SSL_read */ - - switch (nread) { - - case SSL_ERROR_BAD_STATE: - /* there's data pending, re-invoke SSL_Read(). */ - *curlcode = CURLE_AGAIN; - return -1; - - case SSL_ERROR_IO: - switch (errno) { - case EWOULDBLOCK: - *curlcode = CURLE_AGAIN; - return -1; - } - - failf(conn->data, "SSL_Read() I/O error: %s", strerror(errno)); - *curlcode = CURLE_RECV_ERROR; - return -1; - - default: - failf(conn->data, "SSL read error: %s", SSL_Strerror(nread, NULL)); - *curlcode = CURLE_RECV_ERROR; - return -1; - } - } - return (ssize_t) nread; -} - - -size_t Curl_qsossl_version(char * buffer, size_t size) - -{ - strncpy(buffer, "IBM OS/400 SSL", size); - return strlen(buffer); -} - - -int Curl_qsossl_check_cxn(struct connectdata * cxn) - -{ - int err; - int errlen; - - /* The only thing that can be tested here is at the socket level. */ - - if(!cxn->ssl[FIRSTSOCKET].handle) - return 0; /* connection has been closed */ - - err = 0; - errlen = sizeof err; - - if(getsockopt(cxn->sock[FIRSTSOCKET], SOL_SOCKET, SO_ERROR, - (unsigned char *) &err, &errlen) || - errlen != sizeof err || err) - return 0; /* connection has been closed */ - - return -1; /* connection status unknown */ -} - -#endif /* USE_QSOSSL */ diff --git a/Utilities/cmcurl/lib/vtls/qssl.h b/Utilities/cmcurl/lib/vtls/qssl.h deleted file mode 100644 index 9764eec..0000000 --- a/Utilities/cmcurl/lib/vtls/qssl.h +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef HEADER_CURL_QSSL_H -#define HEADER_CURL_QSSL_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at http://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" - -/* - * This header should only be needed to get included by vtls.c and qssl.c - */ - -#include "urldata.h" - -#ifdef USE_QSOSSL -int Curl_qsossl_init(void); -void Curl_qsossl_cleanup(void); -CURLcode Curl_qsossl_connect(struct connectdata * conn, int sockindex); -void Curl_qsossl_close(struct connectdata *conn, int sockindex); -int Curl_qsossl_close_all(struct SessionHandle * data); -int Curl_qsossl_shutdown(struct connectdata * conn, int sockindex); - -size_t Curl_qsossl_version(char * buffer, size_t size); -int Curl_qsossl_check_cxn(struct connectdata * cxn); - -/* API setup for QsoSSL */ -#define curlssl_init Curl_qsossl_init -#define curlssl_cleanup Curl_qsossl_cleanup -#define curlssl_connect Curl_qsossl_connect - -/* No session handling for QsoSSL */ -#define curlssl_session_free(x) Curl_nop_stmt -#define curlssl_close_all Curl_qsossl_close_all -#define curlssl_close Curl_qsossl_close -#define curlssl_shutdown(x,y) Curl_qsossl_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_qsossl_version -#define curlssl_check_cxn(x) Curl_qsossl_check_cxn(x) -#define curlssl_data_pending(x,y) 0 -#define CURL_SSL_BACKEND CURLSSLBACKEND_QSOSSL -#endif /* USE_QSOSSL */ - -#endif /* HEADER_CURL_QSSL_H */ diff --git a/Utilities/cmcurl/lib/vtls/curl_schannel.c b/Utilities/cmcurl/lib/vtls/schannel.c index e4e595e..2174e21 100644 --- a/Utilities/cmcurl/lib/vtls/curl_schannel.c +++ b/Utilities/cmcurl/lib/vtls/schannel.c @@ -5,9 +5,9 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2012 - 2014, Marc Hoersken, <info@marc-hoersken.de> + * Copyright (C) 2012 - 2015, Marc Hoersken, <info@marc-hoersken.de> * Copyright (C) 2012, Mark Salisbury, <mark.salisbury@hp.com> - * Copyright (C) 2012 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2012 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -38,19 +38,6 @@ * Thanks for code and inspiration! */ -/* - * TODO list for TLS/SSL implementation: - * - implement client certificate authentication - * - implement custom server certificate validation - * - implement cipher/algorithm option - * - * Related articles on MSDN: - * - Getting a Certificate for Schannel - * http://msdn.microsoft.com/en-us/library/windows/desktop/aa375447.aspx - * - Specifying Schannel Ciphers and Cipher Strengths - * http://msdn.microsoft.com/en-us/library/windows/desktop/aa380161.aspx - */ - #include "curl_setup.h" #ifdef USE_SCHANNEL @@ -60,7 +47,7 @@ #endif #include "curl_sspi.h" -#include "curl_schannel.h" +#include "schannel.h" #include "vtls.h" #include "sendf.h" #include "connect.h" /* for the connect timeout */ @@ -69,10 +56,7 @@ #include "inet_pton.h" /* for IP addr SNI check */ #include "curl_multibyte.h" #include "warnless.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - +#include "curl_printf.h" #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" @@ -121,13 +105,13 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) struct in6_addr addr6; #endif TCHAR *host_name; - CURLcode code; + CURLcode result; infof(data, "schannel: SSL/TLS connection with %s port %hu (step 1/3)\n", conn->host.name, conn->remote_port); /* check for an existing re-usable credential handle */ - if(!Curl_ssl_getsessionid(conn, (void**)&old_cred, NULL)) { + if(!Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL)) { connssl->cred = old_cred; infof(data, "schannel: re-using existing credential handle\n"); } @@ -141,60 +125,64 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) /* certificate validation on CE doesn't seem to work right; we'll do it following a more manual process. */ schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION | - SCH_CRED_IGNORE_NO_REVOCATION_CHECK | - SCH_CRED_IGNORE_REVOCATION_OFFLINE; + SCH_CRED_IGNORE_NO_REVOCATION_CHECK | + SCH_CRED_IGNORE_REVOCATION_OFFLINE; #else - schannel_cred.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION | - SCH_CRED_REVOCATION_CHECK_CHAIN; + schannel_cred.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION; + if(data->set.ssl_no_revoke) + schannel_cred.dwFlags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK | + SCH_CRED_IGNORE_REVOCATION_OFFLINE; + else + schannel_cred.dwFlags |= SCH_CRED_REVOCATION_CHECK_CHAIN; #endif - infof(data, "schannel: checking server certificate revocation\n"); + if(data->set.ssl_no_revoke) + infof(data, "schannel: disabled server certificate revocation " + "checks\n"); + else + infof(data, "schannel: checking server certificate revocation\n"); } else { schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION | - SCH_CRED_IGNORE_NO_REVOCATION_CHECK | - SCH_CRED_IGNORE_REVOCATION_OFFLINE; - infof(data, "schannel: disable server certificate revocation checks\n"); + SCH_CRED_IGNORE_NO_REVOCATION_CHECK | + SCH_CRED_IGNORE_REVOCATION_OFFLINE; + infof(data, "schannel: disabled server certificate revocation checks\n"); } if(!data->set.ssl.verifyhost) { schannel_cred.dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK; infof(data, "schannel: verifyhost setting prevents Schannel from " - "comparing the supplied target name with the subject " - "names in server certificates. Also disables SNI.\n"); + "comparing the supplied target name with the subject " + "names in server certificates. Also disables SNI.\n"); } switch(data->set.ssl.version) { - case CURL_SSLVERSION_TLSv1: - schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_0_CLIENT | - SP_PROT_TLS1_1_CLIENT | - SP_PROT_TLS1_2_CLIENT; - break; - case CURL_SSLVERSION_TLSv1_0: - schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_0_CLIENT; - break; - case CURL_SSLVERSION_TLSv1_1: - schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_1_CLIENT; - break; - case CURL_SSLVERSION_TLSv1_2: - schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT; - break; - case CURL_SSLVERSION_SSLv3: - schannel_cred.grbitEnabledProtocols = SP_PROT_SSL3_CLIENT; - break; - case CURL_SSLVERSION_SSLv2: - schannel_cred.grbitEnabledProtocols = SP_PROT_SSL2_CLIENT; - break; - default: - schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_0_CLIENT | - SP_PROT_TLS1_1_CLIENT | - SP_PROT_TLS1_2_CLIENT | - SP_PROT_SSL3_CLIENT; - break; + default: + case CURL_SSLVERSION_DEFAULT: + case CURL_SSLVERSION_TLSv1: + schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_0_CLIENT | + SP_PROT_TLS1_1_CLIENT | + SP_PROT_TLS1_2_CLIENT; + break; + case CURL_SSLVERSION_TLSv1_0: + schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_0_CLIENT; + break; + case CURL_SSLVERSION_TLSv1_1: + schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_1_CLIENT; + break; + case CURL_SSLVERSION_TLSv1_2: + schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT; + break; + case CURL_SSLVERSION_SSLv3: + schannel_cred.grbitEnabledProtocols = SP_PROT_SSL3_CLIENT; + break; + case CURL_SSLVERSION_SSLv2: + schannel_cred.grbitEnabledProtocols = SP_PROT_SSL2_CLIENT; + break; } /* allocate memory for the re-usable credential handle */ connssl->cred = (struct curl_schannel_cred *) - malloc(sizeof(struct curl_schannel_cred)); + malloc(sizeof(struct curl_schannel_cred)); if(!connssl->cred) { failf(data, "schannel: unable to allocate memory"); return CURLE_OUT_OF_MEMORY; @@ -202,9 +190,12 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) memset(connssl->cred, 0, sizeof(struct curl_schannel_cred)); /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa374716.aspx */ - sspi_status = s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR *)UNISP_NAME, - SECPKG_CRED_OUTBOUND, NULL, &schannel_cred, NULL, NULL, - &connssl->cred->cred_handle, &connssl->cred->time_stamp); + sspi_status = + s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR *)UNISP_NAME, + SECPKG_CRED_OUTBOUND, NULL, + &schannel_cred, NULL, NULL, + &connssl->cred->cred_handle, + &connssl->cred->time_stamp); if(sspi_status != SEC_E_OK) { if(sspi_status == SEC_E_WRONG_PRINCIPAL) @@ -233,12 +224,12 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) /* setup request flags */ connssl->req_flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT | - ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY | - ISC_REQ_STREAM; + ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY | + ISC_REQ_STREAM; /* allocate memory for the security context handle */ connssl->ctxt = (struct curl_schannel_ctxt *) - malloc(sizeof(struct curl_schannel_ctxt)); + malloc(sizeof(struct curl_schannel_ctxt)); if(!connssl->ctxt) { failf(data, "schannel: unable to allocate memory"); return CURLE_OUT_OF_MEMORY; @@ -273,10 +264,10 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) "sending %lu bytes...\n", outbuf.cbBuffer); /* send initial handshake data which is now stored in output buffer */ - code = Curl_write_plain(conn, conn->sock[sockindex], outbuf.pvBuffer, - outbuf.cbBuffer, &written); + result = Curl_write_plain(conn, conn->sock[sockindex], outbuf.pvBuffer, + outbuf.cbBuffer, &written); s_pSecFn->FreeContextBuffer(outbuf.pvBuffer); - if((code != CURLE_OK) || (outbuf.cbBuffer != (size_t)written)) { + if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) { failf(data, "schannel: failed to send initial handshake data: " "sent %zd of %lu bytes", written, outbuf.cbBuffer); return CURLE_SSL_CONNECT_ERROR; @@ -285,6 +276,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; + /* continue to second handshake step */ connssl->connecting_state = ssl_connect_2; @@ -298,13 +293,15 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) ssize_t nread = -1, written = -1; struct SessionHandle *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - SecBuffer outbuf[2]; + unsigned char *reallocated_buffer; + size_t reallocated_length; + SecBuffer outbuf[3]; SecBufferDesc outbuf_desc; SecBuffer inbuf[2]; SecBufferDesc inbuf_desc; SECURITY_STATUS sspi_status = SEC_E_OK; TCHAR *host_name; - CURLcode code; + CURLcode result; bool doread; doread = (connssl->connecting_state != ssl_connect_2_writing) ? TRUE : FALSE; @@ -315,6 +312,17 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) if(!connssl->cred || !connssl->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) { + 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_offset = 0; @@ -330,31 +338,38 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) if(connssl->encdata_length - connssl->encdata_offset < CURL_SCHANNEL_BUFFER_FREE_SIZE) { /* increase internal encrypted data buffer */ - connssl->encdata_length *= CURL_SCHANNEL_BUFFER_STEP_FACTOR; - connssl->encdata_buffer = realloc(connssl->encdata_buffer, - connssl->encdata_length); + reallocated_length = connssl->encdata_offset + + CURL_SCHANNEL_BUFFER_FREE_SIZE; + reallocated_buffer = realloc(connssl->encdata_buffer, + reallocated_length); - if(connssl->encdata_buffer == NULL) { + if(reallocated_buffer == NULL) { failf(data, "schannel: unable to re-allocate memory"); return CURLE_OUT_OF_MEMORY; } + else { + connssl->encdata_buffer = reallocated_buffer; + connssl->encdata_length = reallocated_length; + } } for(;;) { if(doread) { /* read encrypted handshake data from socket */ - code = Curl_read_plain(conn->sock[sockindex], - (char *) (connssl->encdata_buffer + connssl->encdata_offset), - connssl->encdata_length - connssl->encdata_offset, - &nread); - if(code == CURLE_AGAIN) { + result = Curl_read_plain(conn->sock[sockindex], + (char *) (connssl->encdata_buffer + + connssl->encdata_offset), + connssl->encdata_length - + connssl->encdata_offset, + &nread); + if(result == CURLE_AGAIN) { if(connssl->connecting_state != ssl_connect_2_writing) connssl->connecting_state = ssl_connect_2_reading; infof(data, "schannel: failed to receive handshake, " "need more data\n"); return CURLE_OK; } - else if((code != CURLE_OK) || (nread == 0)) { + else if((result != CURLE_OK) || (nread == 0)) { failf(data, "schannel: failed to receive handshake, " "SSL/TLS connection failed"); return CURLE_SSL_CONNECT_ERROR; @@ -365,7 +380,7 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) } infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n", - connssl->encdata_offset, connssl->encdata_length); + connssl->encdata_offset, connssl->encdata_length); /* setup input buffers */ InitSecBuffer(&inbuf[0], SECBUFFER_TOKEN, malloc(connssl->encdata_offset), @@ -376,7 +391,8 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) /* setup output buffers */ InitSecBuffer(&outbuf[0], SECBUFFER_TOKEN, NULL, 0); InitSecBuffer(&outbuf[1], SECBUFFER_ALERT, NULL, 0); - InitSecBufferDesc(&outbuf_desc, outbuf, 2); + InitSecBuffer(&outbuf[2], SECBUFFER_EMPTY, NULL, 0); + InitSecBufferDesc(&outbuf_desc, outbuf, 3); if(inbuf[0].pvBuffer == NULL) { failf(data, "schannel: unable to allocate memory"); @@ -410,19 +426,31 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) return CURLE_OK; } + /* If the server has requested a client certificate, attempt to continue + 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; + connssl->connecting_state = ssl_connect_2_writing; + infof(data, "schannel: a client certificate has been requested\n"); + return CURLE_OK; + } + /* check if the handshake needs to be continued */ if(sspi_status == SEC_I_CONTINUE_NEEDED || sspi_status == SEC_E_OK) { - for(i = 0; i < 2; i++) { + for(i = 0; i < 3; i++) { /* search for handshake tokens that need to be send */ if(outbuf[i].BufferType == SECBUFFER_TOKEN && outbuf[i].cbBuffer > 0) { infof(data, "schannel: sending next handshake data: " "sending %lu bytes...\n", outbuf[i].cbBuffer); /* send handshake token to server */ - code = Curl_write_plain(conn, conn->sock[sockindex], - outbuf[i].pvBuffer, outbuf[i].cbBuffer, - &written); - if((code != CURLE_OK) || (outbuf[i].cbBuffer != (size_t)written)) { + result = Curl_write_plain(conn, conn->sock[sockindex], + outbuf[i].pvBuffer, outbuf[i].cbBuffer, + &written); + if((result != CURLE_OK) || + (outbuf[i].cbBuffer != (size_t) written)) { failf(data, "schannel: failed to send next handshake data: " "sent %zd of %lu bytes", written, outbuf[i].cbBuffer); return CURLE_SSL_CONNECT_ERROR; @@ -449,21 +477,21 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) if(inbuf[1].BufferType == SECBUFFER_EXTRA && inbuf[1].cbBuffer > 0) { infof(data, "schannel: encrypted data length: %lu\n", inbuf[1].cbBuffer); /* - There are two cases where we could be getting extra data here: - 1) If we're renegotiating a connection and the handshake is already - complete (from the server perspective), it can encrypted app data - (not handshake data) in an extra buffer at this point. - 2) (sspi_status == SEC_I_CONTINUE_NEEDED) We are negotiating a - connection and this extra data is part of the handshake. - We should process the data immediately; waiting for the socket to - be ready may fail since the server is done sending handshake data. - */ + There are two cases where we could be getting extra data here: + 1) If we're renegotiating a connection and the handshake is already + complete (from the server perspective), it can encrypted app data + (not handshake data) in an extra buffer at this point. + 2) (sspi_status == SEC_I_CONTINUE_NEEDED) We are negotiating a + connection and this extra data is part of the handshake. + We should process the data immediately; waiting for the socket to + be ready may fail since the server is done sending handshake data. + */ /* 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) - - inbuf[1].cbBuffer, inbuf[1].cbBuffer); + inbuf[1].cbBuffer, inbuf[1].cbBuffer); connssl->encdata_offset = inbuf[1].cbBuffer; if(sspi_status == SEC_I_CONTINUE_NEEDED) { doread = FALSE; @@ -502,11 +530,11 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) static CURLcode schannel_connect_step3(struct connectdata *conn, int sockindex) { - CURLcode retcode = CURLE_OK; + CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; struct curl_schannel_cred *old_cred = NULL; - int incache; + bool incache; DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); @@ -539,20 +567,21 @@ schannel_connect_step3(struct connectdata *conn, int sockindex) } /* save the current session data for possible re-use */ - incache = !(Curl_ssl_getsessionid(conn, (void**)&old_cred, NULL)); + incache = !(Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL)); if(incache) { if(old_cred != connssl->cred) { infof(data, "schannel: old credential handle is stale, removing\n"); - Curl_ssl_delsessionid(conn, (void*)old_cred); + Curl_ssl_delsessionid(conn, (void *)old_cred); incache = FALSE; } } + if(!incache) { - retcode = Curl_ssl_addsessionid(conn, (void*)connssl->cred, - sizeof(struct curl_schannel_cred)); - if(retcode) { + result = Curl_ssl_addsessionid(conn, (void *)connssl->cred, + sizeof(struct curl_schannel_cred)); + if(result) { failf(data, "schannel: failed to store credential handle"); - return retcode; + return result; } else { connssl->cred->cached = TRUE; @@ -569,7 +598,7 @@ static CURLcode schannel_connect_common(struct connectdata *conn, int sockindex, bool nonblocking, bool *done) { - CURLcode retcode; + CURLcode result; struct SessionHandle *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; curl_socket_t sockfd = conn->sock[sockindex]; @@ -592,9 +621,9 @@ schannel_connect_common(struct connectdata *conn, int sockindex, return CURLE_OPERATION_TIMEDOUT; } - retcode = schannel_connect_step1(conn, sockindex); - if(retcode) - return retcode; + result = schannel_connect_step1(conn, sockindex); + if(result) + return result; } while(ssl_connect_2 == connssl->connecting_state || @@ -646,19 +675,19 @@ schannel_connect_common(struct connectdata *conn, int sockindex, * ensuring that a client using select() or epoll() will always * have a valid fdset to wait on. */ - retcode = schannel_connect_step2(conn, sockindex); - if(retcode || (nonblocking && - (ssl_connect_2 == connssl->connecting_state || - ssl_connect_2_reading == connssl->connecting_state || - ssl_connect_2_writing == connssl->connecting_state))) - return retcode; + result = schannel_connect_step2(conn, sockindex); + if(result || (nonblocking && + (ssl_connect_2 == connssl->connecting_state || + ssl_connect_2_reading == connssl->connecting_state || + ssl_connect_2_writing == connssl->connecting_state))) + return result; } /* repeat step2 until all transactions are done. */ if(ssl_connect_3 == connssl->connecting_state) { - retcode = schannel_connect_step3(conn, sockindex); - if(retcode) - return retcode; + result = schannel_connect_step3(conn, sockindex); + if(result) + return result; } if(ssl_connect_done == connssl->connecting_state) { @@ -687,14 +716,14 @@ schannel_send(struct connectdata *conn, int sockindex, SecBuffer outbuf[4]; SecBufferDesc outbuf_desc; SECURITY_STATUS sspi_status = SEC_E_OK; - CURLcode code; + CURLcode result; /* check if the maximum stream sizes were queried */ if(connssl->stream_sizes.cbMaximumMessage == 0) { sspi_status = s_pSecFn->QueryContextAttributes( - &connssl->ctxt->ctxt_handle, - SECPKG_ATTR_STREAM_SIZES, - &connssl->stream_sizes); + &connssl->ctxt->ctxt_handle, + SECPKG_ATTR_STREAM_SIZES, + &connssl->stream_sizes); if(sspi_status != SEC_E_OK) { *err = CURLE_SEND_ERROR; return -1; @@ -709,8 +738,8 @@ schannel_send(struct connectdata *conn, int sockindex, /* calculate the complete message length and allocate a buffer for it */ data_len = connssl->stream_sizes.cbHeader + len + - connssl->stream_sizes.cbTrailer; - data = (unsigned char*) malloc(data_len); + connssl->stream_sizes.cbTrailer; + data = (unsigned char *) malloc(data_len); if(data == NULL) { *err = CURLE_OUT_OF_MEMORY; return -1; @@ -742,19 +771,19 @@ schannel_send(struct connectdata *conn, int sockindex, len = outbuf[0].cbBuffer + outbuf[1].cbBuffer + outbuf[2].cbBuffer; /* - It's important to send the full message which includes the header, - encrypted payload, and trailer. Until the client receives all the - data a coherent message has not been delivered and the client - can't read any of it. - - If we wanted to buffer the unwritten encrypted bytes, we would - tell the client that all data it has requested to be sent has been - sent. The unwritten encrypted bytes would be the first bytes to - send on the next invocation. - Here's the catch with this - if we tell the client that all the - bytes have been sent, will the client call this method again to - send the buffered data? Looking at who calls this function, it - seems the answer is NO. + It's important to send the full message which includes the header, + encrypted payload, and trailer. Until the client receives all the + data a coherent message has not been delivered and the client + can't read any of it. + + If we wanted to buffer the unwritten encrypted bytes, we would + tell the client that all data it has requested to be sent has been + sent. The unwritten encrypted bytes would be the first bytes to + send on the next invocation. + Here's the catch with this - if we tell the client that all the + bytes have been sent, will the client call this method again to + send the buffered data? Looking at who calls this function, it + seems the answer is NO. */ /* send entire message or fail */ @@ -793,12 +822,12 @@ schannel_send(struct connectdata *conn, int sockindex, } /* socket is writable */ - code = Curl_write_plain(conn, conn->sock[sockindex], data + written, - len - written, &this_write); - if(code == CURLE_AGAIN) + result = Curl_write_plain(conn, conn->sock[sockindex], data + written, + len - written, &this_write); + if(result == CURLE_AGAIN) continue; - else if(code != CURLE_OK) { - *err = code; + else if(result != CURLE_OK) { + *err = result; written = -1; break; } @@ -828,71 +857,112 @@ schannel_recv(struct connectdata *conn, int sockindex, char *buf, size_t len, CURLcode *err) { size_t size = 0; - ssize_t nread = 0, ret = -1; - CURLcode retcode; + ssize_t nread = -1; struct SessionHandle *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + unsigned char *reallocated_buffer; + size_t reallocated_length; bool done = FALSE; SecBuffer inbuf[4]; SecBufferDesc inbuf_desc; SECURITY_STATUS sspi_status = SEC_E_OK; + /* we want the length of the encrypted buffer to be at least large enough + that it can hold all the bytes requested and some TLS record overhead. */ + size_t min_encdata_length = len + CURL_SCHANNEL_BUFFER_FREE_SIZE; + + /**************************************************************************** + * Don't return or set connssl->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 + * possible, even if an error occurs. The state of the decrypted buffer must + * always be valid. Transfer of decrypted data to the caller's buffer is + * handled in the cleanup. + */ infof(data, "schannel: client wants to read %zu bytes\n", len); *err = CURLE_OK; - /* 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) { - failf(data, "schannel: unable to allocate memory"); - *err = CURLE_OUT_OF_MEMORY; - return -1; - } + if(len && len <= connssl->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; + infof(data, "schannel: an unrecoverable error occurred in a prior call\n"); + goto cleanup; + } + else if(connssl->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; + } + else if(!len) { + /* It's debatable what to return when !len. Regardless we can't return + immediately because there may be data to decrypt (in the case we want to + decrypt all encrypted cached data) so handle !len later in cleanup. + */ + ; /* do nothing */ + } + else if(!connssl->recv_connection_closed) { + /* increase enc buffer in order to fit the requested amount of data */ + size = connssl->encdata_length - connssl->encdata_offset; + if(size < CURL_SCHANNEL_BUFFER_FREE_SIZE || + connssl->encdata_length < min_encdata_length) { + reallocated_length = connssl->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_length); + if(reallocated_buffer == NULL) { + *err = CURLE_OUT_OF_MEMORY; + failf(data, "schannel: unable to re-allocate memory"); + goto cleanup; + } - /* increase buffer in order to fit the requested amount of data */ - while(connssl->encdata_length - connssl->encdata_offset < - CURL_SCHANNEL_BUFFER_FREE_SIZE || connssl->encdata_length < len) { - /* increase internal encrypted data buffer */ - connssl->encdata_length *= CURL_SCHANNEL_BUFFER_STEP_FACTOR; - connssl->encdata_buffer = realloc(connssl->encdata_buffer, - connssl->encdata_length); - - if(connssl->encdata_buffer == NULL) { - failf(data, "schannel: unable to re-allocate memory"); - *err = CURLE_OUT_OF_MEMORY; - return -1; + connssl->encdata_buffer = reallocated_buffer; + connssl->encdata_length = reallocated_length; + size = connssl->encdata_length - connssl->encdata_offset; + infof(data, "schannel: encdata_buffer resized %zu\n", + connssl->encdata_length); } - } - /* read encrypted data from socket */ - infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n", - connssl->encdata_offset, connssl->encdata_length); - size = connssl->encdata_length - connssl->encdata_offset; - if(size > 0) { + infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n", + connssl->encdata_offset, connssl->encdata_length); + + /* read encrypted data from socket */ *err = Curl_read_plain(conn->sock[sockindex], - (char *) (connssl->encdata_buffer + connssl->encdata_offset), + (char *)(connssl->encdata_buffer + + connssl->encdata_offset), size, &nread); - /* check for received data */ - if(*err != CURLE_OK) - ret = -1; - else { - if(nread > 0) - /* increase encrypted data buffer offset */ - connssl->encdata_offset += nread; - ret = nread; + if(*err) { + nread = -1; + if(*err == CURLE_AGAIN) + infof(data, "schannel: Curl_read_plain returned CURLE_AGAIN\n"); + else if(*err == CURLE_RECV_ERROR) + infof(data, "schannel: Curl_read_plain returned CURLE_RECV_ERROR\n"); + else + infof(data, "schannel: Curl_read_plain returned error %d\n", *err); + } + else if(nread == 0) { + connssl->recv_connection_closed = true; + infof(data, "schannel: server closed the connection\n"); + } + else if(nread > 0) { + connssl->encdata_offset += (size_t)nread; + infof(data, "schannel: encrypted data got %zd\n", nread); } - infof(data, "schannel: encrypted data got %zd\n", ret); } infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n", connssl->encdata_offset, connssl->encdata_length); - /* check if we still have some data in our buffers */ + /* decrypt loop */ while(connssl->encdata_offset > 0 && sspi_status == SEC_E_OK && - connssl->decdata_offset < len) { + (!len || connssl->decdata_offset < len || + connssl->recv_connection_closed)) { /* prepare data buffer for DecryptMessage call */ InitSecBuffer(&inbuf[0], SECBUFFER_DATA, connssl->encdata_buffer, curlx_uztoul(connssl->encdata_offset)); @@ -901,25 +971,18 @@ schannel_recv(struct connectdata *conn, int sockindex, InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0); InitSecBuffer(&inbuf[2], SECBUFFER_EMPTY, NULL, 0); InitSecBuffer(&inbuf[3], SECBUFFER_EMPTY, NULL, 0); - InitSecBufferDesc(&inbuf_desc, inbuf, 4); /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa375348.aspx */ sspi_status = s_pSecFn->DecryptMessage(&connssl->ctxt->ctxt_handle, &inbuf_desc, 0, NULL); - /* check if we need more data */ - if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) { - infof(data, "schannel: failed to decrypt data, need more data\n"); - *err = CURLE_AGAIN; - return -1; - } - /* check if everything went fine (server may want to renegotiate - context) */ + or shutdown the connection context) */ if(sspi_status == SEC_E_OK || sspi_status == SEC_I_RENEGOTIATE || - sspi_status == SEC_I_CONTEXT_EXPIRED) { - /* check for successfully decrypted data */ + sspi_status == SEC_I_CONTEXT_EXPIRED) { + /* check for successfully decrypted data, even before actual + renegotiation or shutdown of the connection context */ if(inbuf[1].BufferType == SECBUFFER_DATA) { infof(data, "schannel: decrypted data length: %lu\n", inbuf[1].cbBuffer); @@ -927,23 +990,28 @@ 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; - while(connssl->decdata_length - connssl->decdata_offset < size || - connssl->decdata_length < len) { + if(connssl->decdata_length - connssl->decdata_offset < size || + connssl->decdata_length < len) { /* increase internal decrypted data buffer */ - connssl->decdata_length *= CURL_SCHANNEL_BUFFER_STEP_FACTOR; - connssl->decdata_buffer = realloc(connssl->decdata_buffer, - connssl->decdata_length); - - if(connssl->decdata_buffer == NULL) { - failf(data, "schannel: unable to re-allocate memory"); + reallocated_length = connssl->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_length); + if(reallocated_buffer == NULL) { *err = CURLE_OUT_OF_MEMORY; - return -1; + failf(data, "schannel: unable to re-allocate memory"); + goto cleanup; } + connssl->decdata_buffer = reallocated_buffer; + connssl->decdata_length = reallocated_length; } /* copy decrypted data to internal buffer */ size = inbuf[1].cbBuffer; - if(size > 0) { + if(size) { memcpy(connssl->decdata_buffer + connssl->decdata_offset, inbuf[1].pvBuffer, size); connssl->decdata_offset += size; @@ -961,81 +1029,151 @@ 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) { /* move remaining encrypted data forward to the beginning of buffer */ memmove(connssl->encdata_buffer, (connssl->encdata_buffer + connssl->encdata_offset) - - inbuf[3].cbBuffer, inbuf[3].cbBuffer); + inbuf[3].cbBuffer, inbuf[3].cbBuffer); connssl->encdata_offset = inbuf[3].cbBuffer; } infof(data, "schannel: encrypted data cached: offset %zu length %zu\n", connssl->encdata_offset, connssl->encdata_length); } - else{ + else { /* reset encrypted buffer offset, because there is no data remaining */ connssl->encdata_offset = 0; } - } - /* check if server wants to renegotiate the connection context */ - if(sspi_status == SEC_I_RENEGOTIATE) { - infof(data, "schannel: remote party requests SSL/TLS renegotiation\n"); - - /* begin renegotiation */ - infof(data, "schannel: renegotiating SSL/TLS connection\n"); - connssl->state = ssl_connection_negotiating; - connssl->connecting_state = ssl_connect_2_writing; - retcode = schannel_connect_common(conn, sockindex, FALSE, &done); - if(retcode) - *err = retcode; - else { - infof(data, "schannel: SSL/TLS connection renegotiated\n"); + /* check if server wants to renegotiate the connection context */ + if(sspi_status == SEC_I_RENEGOTIATE) { + infof(data, "schannel: remote party requests renegotiation\n"); + if(*err && *err != CURLE_AGAIN) { + infof(data, "schannel: can't renogotiate, an error is pending\n"); + goto cleanup; + } + if(connssl->encdata_offset) { + *err = CURLE_RECV_ERROR; + infof(data, "schannel: can't renogotiate, " + "encrypted data available\n"); + goto cleanup; + } + /* begin renegotiation */ + infof(data, "schannel: renegotiating SSL/TLS connection\n"); + connssl->state = ssl_connection_negotiating; + connssl->connecting_state = ssl_connect_2_writing; + *err = schannel_connect_common(conn, sockindex, FALSE, &done); + if(*err) { + infof(data, "schannel: renegotiation failed\n"); + goto cleanup; + } /* now retry receiving data */ - return schannel_recv(conn, sockindex, buf, len, err); + sspi_status = SEC_E_OK; + infof(data, "schannel: SSL/TLS connection renegotiated\n"); + continue; } + /* check if the server closed the connection */ + 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; + infof(data, "schannel: server closed the connection\n"); + } + goto cleanup; + } + } + else if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) { + if(!*err) + *err = CURLE_AGAIN; + infof(data, "schannel: failed to decrypt data, need more data\n"); + goto cleanup; + } + else { + *err = CURLE_RECV_ERROR; + infof(data, "schannel: failed to read data from server: %s\n", + Curl_sspi_strerror(conn, sspi_status)); + goto cleanup; } } + infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n", + connssl->encdata_offset, connssl->encdata_length); + infof(data, "schannel: decrypted data buffer: offset %zu length %zu\n", connssl->decdata_offset, connssl->decdata_length); - /* copy requested decrypted data to supplied buffer */ +cleanup: + /* Warning- there is no guarantee the encdata state is valid at this point */ + infof(data, "schannel: schannel_recv cleanup\n"); + + /* Error if the connection has closed without a close_notify. + Behavior here is a matter of debate. We don't want to be vulnerable to a + truncation attack however there's some browser precedent for ignoring the + close_notify for compatibility reasons. + Additionally, Windows 2000 (v5.0) is a special case since it seems it doesn't + return close_notify. In that case if the connection was closed we assume it + was graceful (close_notify) since there doesn't seem to be a way to tell. + */ + if(len && !connssl->decdata_offset && connssl->recv_connection_closed && + !connssl->recv_sspi_close_notify) { + BOOL isWin2k; + ULONGLONG cm; + OSVERSIONINFOEX osver; + + memset(&osver, 0, sizeof(osver)); + osver.dwOSVersionInfoSize = sizeof(osver); + osver.dwMajorVersion = 5; + + cm = VerSetConditionMask(0, VER_MAJORVERSION, VER_EQUAL); + cm = VerSetConditionMask(cm, VER_MINORVERSION, VER_EQUAL); + cm = VerSetConditionMask(cm, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL); + cm = VerSetConditionMask(cm, VER_SERVICEPACKMINOR, VER_GREATER_EQUAL); + + isWin2k = VerifyVersionInfo(&osver, + (VER_MAJORVERSION | VER_MINORVERSION | + VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR), + cm); + + if(isWin2k && sspi_status == SEC_E_OK) + connssl->recv_sspi_close_notify = true; + else { + *err = CURLE_RECV_ERROR; + infof(data, "schannel: server closed abruptly (missing close_notify)\n"); + } + } + + /* Any error other than CURLE_AGAIN is an unrecoverable error. */ + if(*err && *err != CURLE_AGAIN) + connssl->recv_unrecoverable_err = *err; + size = len < connssl->decdata_offset ? len : connssl->decdata_offset; - if(size > 0) { + if(size) { memcpy(buf, connssl->decdata_buffer, size); - ret = size; - - /* move remaining decrypted data forward to the beginning of buffer */ memmove(connssl->decdata_buffer, connssl->decdata_buffer + size, connssl->decdata_offset - size); connssl->decdata_offset -= size; - infof(data, "schannel: decrypted data returned %zd\n", 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); - } - - /* check if the server closed the connection */ - if(ret <= 0 && ( /* special check for Windows 2000 Professional */ - sspi_status == SEC_I_CONTEXT_EXPIRED || (sspi_status == SEC_E_OK && - connssl->encdata_offset > 0 && connssl->encdata_buffer[0] == 0x15))) { - infof(data, "schannel: server closed the connection\n"); *err = CURLE_OK; - return 0; + return (ssize_t)size; } - /* check if something went wrong and we need to return an error */ - if(ret < 0 && sspi_status != SEC_E_OK) { - infof(data, "schannel: failed to read data from server: %s\n", - Curl_sspi_strerror(conn, sspi_status)); - *err = CURLE_RECV_ERROR; - return -1; - } + if(!*err && !connssl->recv_connection_closed) + *err = CURLE_AGAIN; + + /* It's debatable what to return when !len. We could return whatever error we + got from decryption but instead we override here so the return is consistent. + */ + if(!len) + *err = CURLE_OK; - return ret; + return *err ? -1 : 0; } CURLcode @@ -1048,12 +1186,12 @@ Curl_schannel_connect_nonblocking(struct connectdata *conn, int sockindex, CURLcode Curl_schannel_connect(struct connectdata *conn, int sockindex) { - CURLcode retcode; + CURLcode result; bool done = FALSE; - retcode = schannel_connect_common(conn, sockindex, FALSE, &done); - if(retcode) - return retcode; + result = schannel_connect_common(conn, sockindex, FALSE, &done); + if(result) + return result; DEBUGASSERT(done); @@ -1095,7 +1233,7 @@ int Curl_schannel_shutdown(struct connectdata *conn, int sockindex) SECURITY_STATUS sspi_status; SecBuffer outbuf; SecBufferDesc outbuf_desc; - CURLcode code; + CURLcode result; TCHAR *host_name; DWORD dwshut = SCHANNEL_SHUTDOWN; @@ -1118,56 +1256,56 @@ 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, - host_name, - connssl->req_flags, - 0, - 0, - NULL, - 0, - &connssl->ctxt->ctxt_handle, - &outbuf_desc, - &connssl->ret_flags, - &connssl->ctxt->time_stamp); + &connssl->cred->cred_handle, + &connssl->ctxt->ctxt_handle, + host_name, + connssl->req_flags, + 0, + 0, + NULL, + 0, + &connssl->ctxt->ctxt_handle, + &outbuf_desc, + &connssl->ret_flags, + &connssl->ctxt->time_stamp); Curl_unicodefree(host_name); if((sspi_status == SEC_E_OK) || (sspi_status == SEC_I_CONTEXT_EXPIRED)) { /* send close message which is in output buffer */ ssize_t written; - code = Curl_write_plain(conn, conn->sock[sockindex], outbuf.pvBuffer, - outbuf.cbBuffer, &written); + result = Curl_write_plain(conn, conn->sock[sockindex], outbuf.pvBuffer, + outbuf.cbBuffer, &written); s_pSecFn->FreeContextBuffer(outbuf.pvBuffer); - if((code != CURLE_OK) || (outbuf.cbBuffer != (size_t)written)) { + if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) { infof(data, "schannel: failed to send close msg: %s" - " (bytes written: %zd)\n", curl_easy_strerror(code), written); + " (bytes written: %zd)\n", curl_easy_strerror(result), written); } } + } - /* free SSPI Schannel API security context handle */ - if(connssl->ctxt) { - infof(data, "schannel: clear security context handle\n"); - s_pSecFn->DeleteSecurityContext(&connssl->ctxt->ctxt_handle); - Curl_safefree(connssl->ctxt); - } + /* free SSPI Schannel API security context handle */ + if(connssl->ctxt) { + infof(data, "schannel: clear security context handle\n"); + s_pSecFn->DeleteSecurityContext(&connssl->ctxt->ctxt_handle); + Curl_safefree(connssl->ctxt); + } - /* free SSPI Schannel API credential handle */ - if(connssl->cred) { - /* decrement the reference counter of the credential/session handle */ - if(connssl->cred->refcount > 0) { - connssl->cred->refcount--; - infof(data, "schannel: decremented credential handle refcount = %d\n", - connssl->cred->refcount); - } + /* free SSPI Schannel API credential handle */ + if(connssl->cred) { + /* decrement the reference counter of the credential/session handle */ + if(connssl->cred->refcount > 0) { + connssl->cred->refcount--; + infof(data, "schannel: decremented credential handle refcount = %d\n", + connssl->cred->refcount); + } - /* if the handle was not cached and the refcount is zero */ - if(!connssl->cred->cached && connssl->cred->refcount == 0) { - infof(data, "schannel: clear credential handle\n"); - s_pSecFn->FreeCredentialsHandle(&connssl->cred->cred_handle); - Curl_safefree(connssl->cred); - } + /* if the handle was not cached and the refcount is zero */ + if(!connssl->cred->cached && connssl->cred->refcount == 0) { + infof(data, "schannel: clear credential handle\n"); + s_pSecFn->FreeCredentialsHandle(&connssl->cred->cred_handle); + Curl_safefree(connssl->cred); } } @@ -1192,9 +1330,14 @@ void Curl_schannel_session_free(void *ptr) { struct curl_schannel_cred *cred = ptr; - if(cred && cred->cached && cred->refcount == 0) { - s_pSecFn->FreeCredentialsHandle(&cred->cred_handle); - Curl_safefree(cred); + if(cred && cred->cached) { + if(cred->refcount == 0) { + s_pSecFn->FreeCredentialsHandle(&cred->cred_handle); + Curl_safefree(cred); + } + else { + cred->cached = FALSE; + } } } @@ -1262,7 +1405,8 @@ static CURLcode verify_certificate(struct connectdata *conn, int sockindex) NULL, pCertContextServer->hCertStore, &ChainPara, - 0, + (data->set.ssl_no_revoke ? 0 : + CERT_CHAIN_REVOCATION_CHECK_CHAIN), NULL, &pChainContext)) { failf(data, "schannel: CertGetCertificateChain failed: %s", @@ -1273,21 +1417,24 @@ static CURLcode verify_certificate(struct connectdata *conn, int sockindex) if(result == CURLE_OK) { CERT_SIMPLE_CHAIN *pSimpleChain = pChainContext->rgpChain[0]; - DWORD dwTrustErrorMask = ~(DWORD)(CERT_TRUST_IS_NOT_TIME_NESTED| - CERT_TRUST_REVOCATION_STATUS_UNKNOWN); + DWORD dwTrustErrorMask = ~(DWORD)(CERT_TRUST_IS_NOT_TIME_NESTED); dwTrustErrorMask &= pSimpleChain->TrustStatus.dwErrorStatus; if(dwTrustErrorMask) { - if(dwTrustErrorMask & CERT_TRUST_IS_PARTIAL_CHAIN) + if(dwTrustErrorMask & CERT_TRUST_IS_REVOKED) + failf(data, "schannel: CertGetCertificateChain trust error" + " CERT_TRUST_IS_REVOKED"); + else if(dwTrustErrorMask & CERT_TRUST_IS_PARTIAL_CHAIN) failf(data, "schannel: CertGetCertificateChain trust error" - " CERT_TRUST_IS_PARTIAL_CHAIN"); - if(dwTrustErrorMask & CERT_TRUST_IS_UNTRUSTED_ROOT) + " CERT_TRUST_IS_PARTIAL_CHAIN"); + else if(dwTrustErrorMask & CERT_TRUST_IS_UNTRUSTED_ROOT) failf(data, "schannel: CertGetCertificateChain trust error" - " CERT_TRUST_IS_UNTRUSTED_ROOT"); - if(dwTrustErrorMask & CERT_TRUST_IS_NOT_TIME_VALID) + " CERT_TRUST_IS_UNTRUSTED_ROOT"); + else if(dwTrustErrorMask & CERT_TRUST_IS_NOT_TIME_VALID) failf(data, "schannel: CertGetCertificateChain trust error" - " CERT_TRUST_IS_NOT_TIME_VALID"); - failf(data, "schannel: CertGetCertificateChain error mask: 0x%08x", - dwTrustErrorMask); + " CERT_TRUST_IS_NOT_TIME_VALID"); + else + failf(data, "schannel: CertGetCertificateChain error mask: 0x%08x", + dwTrustErrorMask); result = CURLE_PEER_FAILED_VERIFICATION; } } @@ -1303,6 +1450,14 @@ static CURLcode verify_certificate(struct connectdata *conn, int sockindex) cert_hostname.const_tchar_ptr = cert_hostname_buff; hostname.tchar_ptr = Curl_convert_UTF8_to_tchar(conn->host.name); + /* TODO: Fix this for certificates with multiple alternative names. + Right now we're only asking for the first preferred alternative name. + Instead we'd need to do all via CERT_NAME_SEARCH_ALL_NAMES_FLAG + (if WinCE supports that?) and run this section in a loop for each. + https://msdn.microsoft.com/en-us/library/windows/desktop/aa376086.aspx + curl: (51) schannel: CertGetNameString() certificate hostname + (.google.com) did not match connection (google.com) + */ len = CertGetNameString(pCertContextServer, CERT_NAME_DNS_TYPE, 0, diff --git a/Utilities/cmcurl/lib/vtls/curl_schannel.h b/Utilities/cmcurl/lib/vtls/schannel.h index 700516b..5329584 100644 --- a/Utilities/cmcurl/lib/vtls/curl_schannel.h +++ b/Utilities/cmcurl/lib/vtls/schannel.h @@ -8,7 +8,7 @@ * \___|\___/|_| \_\_____| * * Copyright (C) 2012, Marc Hoersken, <info@marc-hoersken.de>, et al. - * Copyright (C) 2012 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2012 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -72,30 +72,9 @@ #define SECBUFFER_ALERT 17 #endif -#ifndef ISC_RET_REPLAY_DETECT -#define ISC_RET_REPLAY_DETECT 0x00000004 -#endif - -#ifndef ISC_RET_SEQUENCE_DETECT -#define ISC_RET_SEQUENCE_DETECT 0x00000008 -#endif - -#ifndef ISC_RET_CONFIDENTIALITY -#define ISC_RET_CONFIDENTIALITY 0x00000010 -#endif - -#ifndef ISC_RET_ALLOCATED_MEMORY -#define ISC_RET_ALLOCATED_MEMORY 0x00000100 -#endif - -#ifndef ISC_RET_STREAM -#define ISC_RET_STREAM 0x00008000 -#endif - - +/* Both schannel buffer sizes must be > 0 */ #define CURL_SCHANNEL_BUFFER_INIT_SIZE 4096 #define CURL_SCHANNEL_BUFFER_FREE_SIZE 1024 -#define CURL_SCHANNEL_BUFFER_STEP_FACTOR 2 CURLcode Curl_schannel_connect(struct connectdata *conn, int sockindex); @@ -115,22 +94,24 @@ size_t Curl_schannel_version(char *buffer, size_t size); int Curl_schannel_random(unsigned char *entropy, size_t length); +/* Set the API backend definition to Schannel */ +#define CURL_SSL_BACKEND CURLSSLBACKEND_SCHANNEL + /* 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) (x=x, CURLE_NOT_BUILT_IN) +#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) (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_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) (x=x, -1) +#define curlssl_check_cxn(x) ((void)x, -1) #define curlssl_data_pending Curl_schannel_data_pending -#define CURL_SSL_BACKEND CURLSSLBACKEND_SCHANNEL #define curlssl_random(x,y,z) ((void)x, Curl_schannel_random(y,z)) #endif /* USE_SCHANNEL */ diff --git a/Utilities/cmcurl/lib/vtls/vtls.c b/Utilities/cmcurl/lib/vtls/vtls.c index 88511b8..01bbc61 100644 --- a/Utilities/cmcurl/lib/vtls/vtls.c +++ b/Utilities/cmcurl/lib/vtls/vtls.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -31,7 +31,6 @@ Curl_ossl_ - prefix for OpenSSL ones Curl_gtls_ - prefix for GnuTLS ones Curl_nss_ - prefix for NSS ones - Curl_qssl_ - prefix for QsoSSL ones Curl_gskit_ - prefix for GSKit ones Curl_polarssl_ - prefix for PolarSSL ones Curl_cyassl_ - prefix for CyaSSL ones @@ -60,29 +59,20 @@ #include "urldata.h" #include "vtls.h" /* generic SSL protos etc */ -#include "openssl.h" /* OpenSSL versions */ -#include "gtls.h" /* GnuTLS versions */ -#include "nssg.h" /* NSS versions */ -#include "qssl.h" /* QSOSSL versions */ -#include "gskit.h" /* Global Secure ToolKit versions */ -#include "polarssl.h" /* PolarSSL versions */ -#include "axtls.h" /* axTLS versions */ -#include "cyassl.h" /* CyaSSL versions */ -#include "curl_schannel.h" /* Schannel SSPI version */ -#include "curl_darwinssl.h" /* SecureTransport (Darwin) version */ #include "slist.h" #include "sendf.h" #include "rawstr.h" #include "url.h" -#include "curl_memory.h" #include "progress.h" #include "share.h" #include "timeval.h" +#include "curl_md5.h" +#include "warnless.h" +#include "curl_base64.h" +#include "curl_printf.h" -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - -/* The last #include file should be: */ +/* The last #include files should be: */ +#include "curl_memory.h" #include "memdebug.h" /* convenience macro to check if this handle is using a shared SSL session */ @@ -193,7 +183,7 @@ void Curl_free_ssl_config(struct ssl_config_data* sslc) unsigned int Curl_rand(struct SessionHandle *data) { - unsigned int r; + unsigned int r = 0; static unsigned int randseed; static bool seeded = FALSE; @@ -286,47 +276,66 @@ void Curl_ssl_cleanup(void) } } +static bool ssl_prefs_check(struct SessionHandle *data) +{ + /* check for CURLOPT_SSLVERSION invalid parameter value */ + if((data->set.ssl.version < 0) + || (data->set.ssl.version >= CURL_SSLVERSION_LAST)) { + failf(data, "Unrecognized parameter value passed via CURLOPT_SSLVERSION"); + return FALSE; + } + return TRUE; +} + CURLcode Curl_ssl_connect(struct connectdata *conn, int sockindex) { - CURLcode res; + CURLcode result; + + if(!ssl_prefs_check(conn->data)) + return CURLE_SSL_CONNECT_ERROR; + /* mark this is being ssl-enabled from here on. */ conn->ssl[sockindex].use = TRUE; conn->ssl[sockindex].state = ssl_connection_negotiating; - res = curlssl_connect(conn, sockindex); + result = curlssl_connect(conn, sockindex); - if(!res) + if(!result) Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSL is connected */ - return res; + return result; } CURLcode Curl_ssl_connect_nonblocking(struct connectdata *conn, int sockindex, bool *done) { - CURLcode res; + CURLcode result; + + if(!ssl_prefs_check(conn->data)) + return CURLE_SSL_CONNECT_ERROR; + /* mark this is being ssl requested from here on. */ conn->ssl[sockindex].use = TRUE; #ifdef curlssl_connect_nonblocking - res = curlssl_connect_nonblocking(conn, sockindex, done); + result = curlssl_connect_nonblocking(conn, sockindex, done); #else *done = TRUE; /* fallback to BLOCKING */ - res = curlssl_connect(conn, sockindex); + result = curlssl_connect(conn, sockindex); #endif /* non-blocking connect support */ - if(!res && *done) + if(!result && *done) Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSL is connected */ - return res; + return result; } /* * Check if there's a session ID for the given connection in the cache, and if * there's one suitable, it is provided. Returns TRUE when no entry matched. */ -int Curl_ssl_getsessionid(struct connectdata *conn, - void **ssl_sessionid, - size_t *idsize) /* set 0 if unknown */ +bool Curl_ssl_getsessionid(struct connectdata *conn, + void **ssl_sessionid, + size_t *idsize) /* set 0 if unknown */ { struct curl_ssl_session *check; struct SessionHandle *data = conn->data; @@ -473,9 +482,8 @@ CURLcode Curl_ssl_addsessionid(struct connectdata *conn, store->sessionid = ssl_sessionid; store->idsize = idsize; store->age = *general_age; /* set current age */ - if(store->name) /* free it if there's one already present */ - free(store->name); + free(store->name); store->name = clone_host; /* clone host name */ store->remote_port = conn->remote_port; /* port number */ @@ -601,34 +609,37 @@ void Curl_ssl_free_certinfo(struct SessionHandle *data) { int i; struct curl_certinfo *ci = &data->info.certs; + if(ci->num_of_certs) { /* free all individual lists used */ for(i=0; i<ci->num_of_certs; i++) { curl_slist_free_all(ci->certinfo[i]); ci->certinfo[i] = NULL; } + free(ci->certinfo); /* free the actual array too */ ci->certinfo = NULL; ci->num_of_certs = 0; } } -int Curl_ssl_init_certinfo(struct SessionHandle * data, - int num) +CURLcode Curl_ssl_init_certinfo(struct SessionHandle *data, int num) { - struct curl_certinfo * ci = &data->info.certs; - struct curl_slist * * table; + struct curl_certinfo *ci = &data->info.certs; + struct curl_slist **table; - /* Initialize the certificate information structures. Return 0 if OK, else 1. - */ + /* Free any previous certificate information structures */ Curl_ssl_free_certinfo(data); - ci->num_of_certs = num; + + /* Allocate the required certificate information structures */ table = calloc((size_t) num, sizeof(struct curl_slist *)); if(!table) - return 1; + return CURLE_OUT_OF_MEMORY; + ci->num_of_certs = num; ci->certinfo = table; - return 0; + + return CURLE_OK; } /* @@ -643,7 +654,7 @@ CURLcode Curl_ssl_push_certinfo_len(struct SessionHandle *data, struct curl_certinfo * ci = &data->info.certs; char * output; struct curl_slist * nl; - CURLcode res = CURLE_OK; + CURLcode result = CURLE_OK; size_t labellen = strlen(label); size_t outlen = labellen + 1 + valuelen + 1; /* label:value\0 */ @@ -664,11 +675,11 @@ CURLcode Curl_ssl_push_certinfo_len(struct SessionHandle *data, if(!nl) { free(output); curl_slist_free_all(ci->certinfo[certnum]); - res = CURLE_OUT_OF_MEMORY; + result = CURLE_OUT_OF_MEMORY; } ci->certinfo[certnum] = nl; - return res; + return result; } /* @@ -692,14 +703,260 @@ int Curl_ssl_random(struct SessionHandle *data, return curlssl_random(data, entropy, length); } -#ifdef have_curlssl_md5sum -void Curl_ssl_md5sum(unsigned char *tmp, /* input */ - size_t tmplen, - unsigned char *md5sum, /* output */ - size_t md5len) +/* + * Public key pem to der conversion + */ + +static CURLcode pubkey_pem_to_der(const char *pem, + unsigned char **der, size_t *der_len) +{ + char *stripped_pem, *begin_pos, *end_pos; + size_t pem_count, stripped_pem_count = 0, pem_len; + CURLcode result; + + /* if no pem, exit. */ + if(!pem) + return CURLE_BAD_CONTENT_ENCODING; + + begin_pos = strstr(pem, "-----BEGIN PUBLIC KEY-----"); + if(!begin_pos) + return CURLE_BAD_CONTENT_ENCODING; + + pem_count = begin_pos - pem; + /* Invalid if not at beginning AND not directly following \n */ + if(0 != pem_count && '\n' != pem[pem_count - 1]) + return CURLE_BAD_CONTENT_ENCODING; + + /* 26 is length of "-----BEGIN PUBLIC KEY-----" */ + pem_count += 26; + + /* Invalid if not directly following \n */ + end_pos = strstr(pem + pem_count, "\n-----END PUBLIC KEY-----"); + if(!end_pos) + return CURLE_BAD_CONTENT_ENCODING; + + pem_len = end_pos - pem; + + stripped_pem = malloc(pem_len - pem_count + 1); + if(!stripped_pem) + return CURLE_OUT_OF_MEMORY; + + /* + * Here we loop through the pem array one character at a time between the + * correct indices, and place each character that is not '\n' or '\r' + * into the stripped_pem array, which should represent the raw base64 string + */ + while(pem_count < pem_len) { + if('\n' != pem[pem_count] && '\r' != pem[pem_count]) + stripped_pem[stripped_pem_count++] = pem[pem_count]; + ++pem_count; + } + /* Place the null terminator in the correct place */ + stripped_pem[stripped_pem_count] = '\0'; + + result = Curl_base64_decode(stripped_pem, der, der_len); + + Curl_safefree(stripped_pem); + + return result; +} + +/* + * Generic pinned public key check. + */ + +CURLcode Curl_pin_peer_pubkey(const char *pinnedpubkey, + const unsigned char *pubkey, size_t pubkeylen) { + FILE *fp; + unsigned char *buf = NULL, *pem_ptr = NULL; + long filesize; + size_t size, pem_len; + CURLcode pem_read; + CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH; +#ifdef curlssl_sha256sum + size_t pinkeylen; + char *pinkeycopy, *begin_pos, *end_pos; + unsigned char *sha256sumdigest = NULL, *expectedsha256sumdigest = NULL; +#endif + + /* if a path wasn't specified, don't pin */ + if(!pinnedpubkey) + return CURLE_OK; + if(!pubkey || !pubkeylen) + return result; + +#ifdef curlssl_sha256sum + /* only do this if pinnedpubkey starts with "sha256//", length 8 */ + if(strncmp(pinnedpubkey, "sha256//", 8) == 0) { + /* compute sha256sum of public key */ + sha256sumdigest = malloc(SHA256_DIGEST_LENGTH); + if(!sha256sumdigest) + return CURLE_OUT_OF_MEMORY; + curlssl_sha256sum(pubkey, pubkeylen, + sha256sumdigest, SHA256_DIGEST_LENGTH); + + /* it starts with sha256//, copy so we can modify it */ + pinkeylen = strlen(pinnedpubkey) + 1; + pinkeycopy = malloc(pinkeylen); + if(!pinkeycopy) { + Curl_safefree(sha256sumdigest); + return CURLE_OUT_OF_MEMORY; + } + memcpy(pinkeycopy, pinnedpubkey, pinkeylen); + /* point begin_pos to the copy, and start extracting keys */ + begin_pos = pinkeycopy; + do { + end_pos = strstr(begin_pos, ";sha256//"); + /* + * if there is an end_pos, null terminate, + * otherwise it'll go to the end of the original string + */ + if(end_pos) + end_pos[0] = '\0'; + + /* decode base64 pinnedpubkey, 8 is length of "sha256//" */ + pem_read = Curl_base64_decode(begin_pos + 8, + &expectedsha256sumdigest, &size); + /* if not valid base64, don't bother comparing or freeing */ + if(!pem_read) { + /* compare sha256 digests directly */ + if(SHA256_DIGEST_LENGTH == size && + !memcmp(sha256sumdigest, expectedsha256sumdigest, + SHA256_DIGEST_LENGTH)) { + result = CURLE_OK; + Curl_safefree(expectedsha256sumdigest); + break; + } + Curl_safefree(expectedsha256sumdigest); + } + + /* + * change back the null-terminator we changed earlier, + * and look for next begin + */ + if(end_pos) { + end_pos[0] = ';'; + begin_pos = strstr(end_pos, "sha256//"); + } + } while(end_pos && begin_pos); + Curl_safefree(sha256sumdigest); + Curl_safefree(pinkeycopy); + return result; + } +#endif + + fp = fopen(pinnedpubkey, "rb"); + if(!fp) + return result; + + do { + /* Determine the file's size */ + if(fseek(fp, 0, SEEK_END)) + break; + filesize = ftell(fp); + if(fseek(fp, 0, SEEK_SET)) + break; + if(filesize < 0 || filesize > MAX_PINNED_PUBKEY_SIZE) + break; + + /* + * if the size of our certificate is bigger than the file + * size then it can't match + */ + size = curlx_sotouz((curl_off_t) filesize); + if(pubkeylen > size) + break; + + /* + * Allocate buffer for the pinned key + * With 1 additional byte for null terminator in case of PEM key + */ + buf = malloc(size + 1); + if(!buf) + break; + + /* Returns number of elements read, which should be 1 */ + if((int) fread(buf, size, 1, fp) != 1) + break; + + /* If the sizes are the same, it can't be base64 encoded, must be der */ + if(pubkeylen == size) { + if(!memcmp(pubkey, buf, pubkeylen)) + result = CURLE_OK; + break; + } + + /* + * Otherwise we will assume it's PEM and try to decode it + * after placing null terminator + */ + buf[size] = '\0'; + pem_read = pubkey_pem_to_der((const char *)buf, &pem_ptr, &pem_len); + /* if it wasn't read successfully, exit */ + if(pem_read) + break; + + /* + * if the size of our certificate doesn't match the size of + * the decoded file, they can't be the same, otherwise compare + */ + if(pubkeylen == pem_len && !memcmp(pubkey, pem_ptr, pubkeylen)) + result = CURLE_OK; + } while(0); + + Curl_safefree(buf); + Curl_safefree(pem_ptr); + fclose(fp); + + return result; +} + +#ifndef CURL_DISABLE_CRYPTO_AUTH +CURLcode Curl_ssl_md5sum(unsigned char *tmp, /* input */ + size_t tmplen, + 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; +} +#endif + +/* + * Check whether the SSL backend supports the status_request extension. + */ +bool Curl_ssl_cert_status_request(void) +{ +#ifdef curlssl_cert_status_request + return curlssl_cert_status_request(); +#else + return FALSE; +#endif } + +/* + * Check whether the SSL backend supports false start. + */ +bool Curl_ssl_false_start(void) +{ +#ifdef curlssl_false_start + return curlssl_false_start(); +#else + return FALSE; #endif +} #endif /* USE_SSL */ diff --git a/Utilities/cmcurl/lib/vtls/vtls.h b/Utilities/cmcurl/lib/vtls/vtls.h index e21fdef..2349e5b 100644 --- a/Utilities/cmcurl/lib/vtls/vtls.h +++ b/Utilities/cmcurl/lib/vtls/vtls.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -23,10 +23,28 @@ ***************************************************************************/ #include "curl_setup.h" +#include "openssl.h" /* OpenSSL versions */ +#include "gtls.h" /* GnuTLS versions */ +#include "nssg.h" /* NSS versions */ +#include "gskit.h" /* Global Secure ToolKit versions */ +#include "polarssl.h" /* PolarSSL versions */ +#include "axtls.h" /* axTLS versions */ +#include "cyassl.h" /* CyaSSL versions */ +#include "schannel.h" /* Schannel SSPI version */ +#include "darwinssl.h" /* SecureTransport (Darwin) version */ + +#ifndef MAX_PINNED_PUBKEY_SIZE +#define MAX_PINNED_PUBKEY_SIZE 1048576 /* 1MB */ +#endif + #ifndef MD5_DIGEST_LENGTH #define MD5_DIGEST_LENGTH 16 /* fixed size */ #endif +#ifndef SHA256_DIGEST_LENGTH +#define SHA256_DIGEST_LENGTH 32 /* fixed size */ +#endif + /* see http://tools.ietf.org/html/draft-ietf-tls-applayerprotoneg-04 */ #define ALPN_HTTP_1_1_LENGTH 8 #define ALPN_HTTP_1_1 "http/1.1" @@ -68,7 +86,7 @@ int Curl_ssl_check_cxn(struct connectdata *conn); /* Certificate information list handling. */ void Curl_ssl_free_certinfo(struct SessionHandle *data); -int Curl_ssl_init_certinfo(struct SessionHandle * data, int num); +CURLcode Curl_ssl_init_certinfo(struct SessionHandle * data, int num); CURLcode Curl_ssl_push_certinfo_len(struct SessionHandle * data, int certnum, const char * label, const char * value, size_t valuelen); @@ -78,9 +96,9 @@ CURLcode Curl_ssl_push_certinfo(struct SessionHandle * data, int certnum, /* Functions to be used by SSL library adaptation functions */ /* extract a session ID */ -int Curl_ssl_getsessionid(struct connectdata *conn, - void **ssl_sessionid, - size_t *idsize) /* set 0 if unknown */; +bool Curl_ssl_getsessionid(struct connectdata *conn, + void **ssl_sessionid, + size_t *idsize) /* set 0 if unknown */; /* add a new session ID */ CURLcode Curl_ssl_addsessionid(struct connectdata *conn, void *ssl_sessionid, @@ -94,18 +112,24 @@ void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid); in */ int Curl_ssl_random(struct SessionHandle *data, unsigned char *buffer, size_t length); -void Curl_ssl_md5sum(unsigned char *tmp, /* input */ - size_t tmplen, - unsigned char *md5sum, /* output */ - size_t md5len); +CURLcode Curl_ssl_md5sum(unsigned char *tmp, /* input */ + size_t tmplen, + unsigned char *md5sum, /* output */ + size_t md5len); +/* Check pinned public key. */ +CURLcode Curl_pin_peer_pubkey(const char *pinnedpubkey, + const unsigned char *pubkey, size_t pubkeylen); -#define SSL_SHUTDOWN_TIMEOUT 10000 /* ms */ +bool Curl_ssl_cert_status_request(void); -#ifdef have_curlssl_md5sum -#define HAVE_CURL_SSL_MD5SUM -#endif +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 #define Curl_ssl_cleanup() Curl_nop_stmt @@ -125,8 +149,9 @@ void Curl_ssl_md5sum(unsigned char *tmp, /* input */ #define Curl_ssl_free_certinfo(x) Curl_nop_stmt #define Curl_ssl_connect_nonblocking(x,y,z) CURLE_NOT_BUILT_IN #define Curl_ssl_kill_session(x) Curl_nop_stmt -#define Curl_ssl_random(x,y,z) CURLE_NOT_BUILT_IN -#define CURL_SSL_BACKEND CURLSSLBACKEND_NONE +#define Curl_ssl_random(x,y,z) ((void)x, CURLE_NOT_BUILT_IN) +#define Curl_ssl_cert_status_request() FALSE +#define Curl_ssl_false_start() FALSE #endif #endif /* HEADER_CURL_VTLS_H */ diff --git a/Utilities/cmcurl/lib/wildcard.c b/Utilities/cmcurl/lib/wildcard.c index 7130d5e..6f55839 100644 --- a/Utilities/cmcurl/lib/wildcard.c +++ b/Utilities/cmcurl/lib/wildcard.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -25,10 +25,7 @@ #include "wildcard.h" #include "llist.h" #include "fileinfo.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - +#include "curl_printf.h" #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" @@ -62,15 +59,10 @@ void Curl_wildcard_dtor(struct WildcardData *wc) wc->filelist = NULL; } - if(wc->path) { - free(wc->path); - wc->path = NULL; - } - - if(wc->pattern) { - free(wc->pattern); - wc->pattern = NULL; - } + free(wc->path); + wc->path = NULL; + free(wc->pattern); + wc->pattern = NULL; wc->customptr = NULL; wc->state = CURLWC_INIT; diff --git a/Utilities/cmcurl/lib/x509asn1.c b/Utilities/cmcurl/lib/x509asn1.c index 1f87155..a3dfd64 100644 --- a/Utilities/cmcurl/lib/x509asn1.c +++ b/Utilities/cmcurl/lib/x509asn1.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -22,7 +22,8 @@ #include "curl_setup.h" -#if defined(USE_QSOSSL) || defined(USE_GSKIT) || defined(USE_NSS) +#if defined(USE_GSKIT) || defined(USE_NSS) || defined(USE_GNUTLS) || \ + defined(USE_CYASSL) #include <curl/curl.h> #include "urldata.h" @@ -33,10 +34,7 @@ #include "inet_pton.h" #include "curl_base64.h" #include "x509asn1.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - +#include "curl_printf.h" #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" @@ -122,6 +120,7 @@ const char * Curl_getASN1Element(curl_asn1Element * elem, return (const char *) NULL; /* Process header byte. */ + elem->header = beg; b = (unsigned char) *beg++; elem->constructed = (b & 0x20) != 0; elem->class = (b >> 6) & 3; @@ -211,7 +210,6 @@ static const char * octet2str(const char * beg, const char * end) } static const char * bit2str(const char * beg, const char * end) - { /* Convert an ASN.1 bit string to a printable string. Return the dynamically allocated string, or NULL if an error occurs. */ @@ -300,8 +298,10 @@ utf8asn1str(char * * to, int type, const char * from, const char * end) case 4: wc = (wc << 8) | *(const unsigned char *) from++; wc = (wc << 8) | *(const unsigned char *) from++; + /* fallthrough */ case 2: wc = (wc << 8) | *(const unsigned char *) from++; + /* fallthrough */ default: /* case 1: */ wc = (wc << 8) | *(const unsigned char *) from++; } @@ -539,8 +539,6 @@ static const char * UTime2str(const char * beg, const char * end) const char * Curl_ASN1tostr(curl_asn1Element * elem, int type) { - static const char zero = '\0'; - /* Convert an ASN.1 element to a printable string. Return the dynamically allocated string, or NULL if an error occurs. */ @@ -561,7 +559,7 @@ const char * Curl_ASN1tostr(curl_asn1Element * elem, int type) case CURL_ASN1_OCTET_STRING: return octet2str(elem->beg, elem->end); case CURL_ASN1_NULL: - return strdup(&zero); + return strdup(""); case CURL_ASN1_OBJECT_IDENTIFIER: return OID2str(elem->beg, elem->end, TRUE); case CURL_ASN1_UTC_TIME: @@ -682,6 +680,7 @@ void Curl_parseX509(curl_X509certificate * cert, Syntax is assumed to have already been checked by the SSL backend. See RFC 5280. */ + cert->certificate.header = NULL; cert->certificate.beg = beg; cert->certificate.end = end; @@ -701,6 +700,7 @@ void Curl_parseX509(curl_X509certificate * cert, beg = tbsCertificate.beg; end = tbsCertificate.end; /* Get optional version, get serialNumber. */ + cert->version.header = NULL; cert->version.beg = &defaultVersion; cert->version.end = &defaultVersion + sizeof defaultVersion;; beg = Curl_getASN1Element(&elem, beg, end); @@ -720,15 +720,19 @@ void Curl_parseX509(curl_X509certificate * cert, /* Get subject. */ beg = Curl_getASN1Element(&cert->subject, beg, end); /* Get subjectPublicKeyAlgorithm and subjectPublicKey. */ - beg = Curl_getASN1Element(&elem, beg, end); + beg = Curl_getASN1Element(&cert->subjectPublicKeyInfo, beg, end); ccp = Curl_getASN1Element(&cert->subjectPublicKeyAlgorithm, - elem.beg, elem.end); - Curl_getASN1Element(&cert->subjectPublicKey, ccp, elem.end); + cert->subjectPublicKeyInfo.beg, + cert->subjectPublicKeyInfo.end); + Curl_getASN1Element(&cert->subjectPublicKey, ccp, + cert->subjectPublicKeyInfo.end); /* Get optional issuerUiqueID, subjectUniqueID and extensions. */ cert->issuerUniqueID.tag = cert->subjectUniqueID.tag = 0; cert->extensions.tag = elem.tag = 0; + cert->issuerUniqueID.header = cert->subjectUniqueID.header = NULL; cert->issuerUniqueID.beg = cert->issuerUniqueID.end = ""; cert->subjectUniqueID.beg = cert->subjectUniqueID.end = ""; + cert->extensions.header = NULL; cert->extensions.beg = cert->extensions.end = ""; if(beg < end) beg = Curl_getASN1Element(&elem, beg, end); @@ -771,6 +775,7 @@ static const char * dumpAlgo(curl_asn1Element * param, /* Get algorithm parameters and return algorithm name. */ beg = Curl_getASN1Element(&oid, beg, end); + param->header = NULL; param->tag = 0; param->beg = param->end = end; if(beg < end) @@ -816,7 +821,7 @@ static void do_pubkey(struct SessionHandle * data, int certnum, /* Compute key length. */ for(q = elem.beg; !*q && q < elem.end; q++) ; - len = (elem.end - q) * 8; + len = (unsigned long)((elem.end - q) * 8); if(len) for(i = *(unsigned char *) q; !(i & 0x80); i <<= 1) len--; @@ -871,7 +876,7 @@ CURLcode Curl_extract_certinfo(struct connectdata * conn, char * cp1; size_t cl1; char * cp2; - CURLcode cc; + CURLcode result; unsigned long version; size_t i; size_t j; @@ -985,11 +990,11 @@ CURLcode Curl_extract_certinfo(struct connectdata * conn, free((char *) ccp); /* Generate PEM certificate. */ - cc = Curl_base64_encode(data, cert.certificate.beg, - cert.certificate.end - cert.certificate.beg, - &cp1, &cl1); - if(cc != CURLE_OK) - return cc; + result = Curl_base64_encode(data, cert.certificate.beg, + cert.certificate.end - cert.certificate.beg, + &cp1, &cl1); + if(result) + return result; /* Compute the number of characters in final certificate string. Format is: -----BEGIN CERTIFICATE-----\n <max 64 base64 characters>\n @@ -1019,9 +1024,9 @@ CURLcode Curl_extract_certinfo(struct connectdata * conn, return CURLE_OK; } -#endif /* USE_QSOSSL or USE_GSKIT or USE_NSS */ +#endif /* USE_GSKIT or USE_NSS or USE_GNUTLS or USE_CYASSL */ -#if defined(USE_QSOSSL) || defined(USE_GSKIT) +#if defined(USE_GSKIT) static const char * checkOID(const char * beg, const char * end, const char * oid) @@ -1111,8 +1116,7 @@ CURLcode Curl_verifyhost(struct connectdata * conn, if(len > 0) if(strlen(dnsname) == (size_t) len) i = Curl_cert_hostcheck((const char *) dnsname, conn->host.name); - if(dnsname) - free(dnsname); + free(dnsname); if(!i) return CURLE_PEER_FAILED_VERIFICATION; matched = i; @@ -1140,6 +1144,7 @@ CURLcode Curl_verifyhost(struct connectdata * conn, } /* Process subject. */ + name.header = NULL; name.beg = name.end = ""; q = cert.subject.beg; /* we have to look to the last occurrence of a commonName in the @@ -1180,4 +1185,4 @@ CURLcode Curl_verifyhost(struct connectdata * conn, return CURLE_PEER_FAILED_VERIFICATION; } -#endif /* USE_QSOSSL or USE_GSKIT */ +#endif /* USE_GSKIT */ diff --git a/Utilities/cmcurl/lib/x509asn1.h b/Utilities/cmcurl/lib/x509asn1.h index 1741d6d..eb23e50 100644 --- a/Utilities/cmcurl/lib/x509asn1.h +++ b/Utilities/cmcurl/lib/x509asn1.h @@ -8,7 +8,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -25,7 +25,8 @@ #include "curl_setup.h" -#if defined(USE_QSOSSL) || defined(USE_GSKIT) || defined(USE_NSS) +#if defined(USE_GSKIT) || defined(USE_NSS) || defined(USE_GNUTLS) || \ + defined(USE_CYASSL) #include "urldata.h" @@ -76,8 +77,9 @@ /* ASN.1 parsed element. */ typedef struct { + const char * header; /* Pointer to header byte. */ const char * beg; /* Pointer to element data. */ - const char * end; /* Pointer to 1st byte after element data. */ + const char * end; /* Pointer to 1st byte after element. */ unsigned char class; /* ASN.1 element class. */ unsigned char tag; /* ASN.1 element tag. */ bool constructed; /* Element is constructed. */ @@ -102,6 +104,7 @@ typedef struct { curl_asn1Element notBefore; curl_asn1Element notAfter; curl_asn1Element subject; + curl_asn1Element subjectPublicKeyInfo; curl_asn1Element subjectPublicKeyAlgorithm; curl_asn1Element subjectPublicKey; curl_asn1Element issuerUniqueID; @@ -125,5 +128,5 @@ CURLcode Curl_extract_certinfo(struct connectdata * conn, int certnum, CURLcode Curl_verifyhost(struct connectdata * conn, const char * beg, const char * end); -#endif /* USE_QSOSSL or USE_GSKIT or USE_NSS */ +#endif /* USE_GSKIT or USE_NSS or USE_GNUTLS or USE_CYASSL */ #endif /* HEADER_CURL_X509ASN1_H */ |