summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Auxiliary/cmake-mode.el4
-rw-r--r--CMakeLists.txt2
-rw-r--r--CTestCustom.cmake.in4
-rw-r--r--Help/command/if.rst4
-rw-r--r--Help/command/string.rst2
-rw-r--r--Help/command/try_compile.rst11
-rw-r--r--Help/manual/cmake-policies.7.rst1
-rw-r--r--Help/manual/cmake-variables.7.rst2
-rw-r--r--Help/manual/cmake.1.rst2
-rw-r--r--Help/policy/CMP0064.rst17
-rw-r--r--Help/prop_gbl/RULE_LAUNCH_COMPILE.rst10
-rw-r--r--Help/prop_gbl/RULE_LAUNCH_CUSTOM.rst10
-rw-r--r--Help/prop_gbl/RULE_LAUNCH_LINK.rst10
-rw-r--r--Help/prop_tgt/ARCHIVE_OUTPUT_DIRECTORY_CONFIG.rst3
-rw-r--r--Help/prop_tgt/LIBRARY_OUTPUT_DIRECTORY_CONFIG.rst3
-rw-r--r--Help/prop_tgt/LINK_SEARCH_END_STATIC.rst8
-rw-r--r--Help/prop_tgt/LINK_SEARCH_START_STATIC.rst7
-rw-r--r--Help/prop_tgt/RUNTIME_OUTPUT_DIRECTORY_CONFIG.rst3
-rw-r--r--Help/prop_tgt/XXX_OUTPUT_DIRECTORY.txt7
-rw-r--r--Help/release/dev/FindTIFF-updates.rst5
-rw-r--r--Help/release/dev/FindXercesC-updates.rst5
-rw-r--r--Help/release/dev/OUTPUT_DIRECTORY-genex.rst7
-rw-r--r--Help/release/dev/add-link-search-static-properties-defaults.rst9
-rw-r--r--Help/release/dev/if-TEST.rst5
-rw-r--r--Help/release/dev/java-updates.rst13
-rw-r--r--Help/variable/APPLE.rst4
-rw-r--r--Help/variable/BORLAND.rst4
-rw-r--r--Help/variable/BUILD_SHARED_LIBS.rst6
-rw-r--r--Help/variable/CMAKE_ABSOLUTE_DESTINATION_FILES.rst4
-rw-r--r--Help/variable/CMAKE_ANDROID_NATIVE_LIB_DEPENDENCIES.rst4
-rw-r--r--Help/variable/CMAKE_ANDROID_NATIVE_LIB_DIRECTORIES.rst4
-rw-r--r--Help/variable/CMAKE_ARGC.rst5
-rw-r--r--Help/variable/CMAKE_ARGV0.rst8
-rw-r--r--Help/variable/CMAKE_AUTOMOC_RELAXED_MODE.rst12
-rw-r--r--Help/variable/CMAKE_AUTORCC.rst4
-rw-r--r--Help/variable/CMAKE_AUTOUIC.rst4
-rw-r--r--Help/variable/CMAKE_BINARY_DIR.rst2
-rw-r--r--Help/variable/CMAKE_BUILD_TYPE.rst25
-rw-r--r--Help/variable/CMAKE_BUILD_WITH_INSTALL_RPATH.rst10
-rw-r--r--Help/variable/CMAKE_CACHEFILE_DIR.rst6
-rw-r--r--Help/variable/CMAKE_CACHE_MAJOR_VERSION.rst2
-rw-r--r--Help/variable/CMAKE_CACHE_MINOR_VERSION.rst2
-rw-r--r--Help/variable/CMAKE_CACHE_PATCH_VERSION.rst2
-rw-r--r--Help/variable/CMAKE_CFG_INTDIR.rst21
-rw-r--r--Help/variable/CMAKE_CL_64.rst4
-rw-r--r--Help/variable/CMAKE_COLOR_MAKEFILE.rst4
-rw-r--r--Help/variable/CMAKE_COMMAND.rst8
-rw-r--r--Help/variable/CMAKE_COMPILER_IS_GNULANG.rst6
-rw-r--r--Help/variable/CMAKE_CONFIGURATION_TYPES.rst6
-rw-r--r--Help/variable/CMAKE_CONFIG_POSTFIX.rst6
-rw-r--r--Help/variable/CMAKE_CTEST_COMMAND.rst8
-rw-r--r--Help/variable/CMAKE_CURRENT_BINARY_DIR.rst2
-rw-r--r--Help/variable/CMAKE_CURRENT_LIST_DIR.rst6
-rw-r--r--Help/variable/CMAKE_CURRENT_LIST_FILE.rst2
-rw-r--r--Help/variable/CMAKE_CXX_COMPILE_FEATURES.rst4
-rw-r--r--Help/variable/CMAKE_CXX_EXTENSIONS.rst2
-rw-r--r--Help/variable/CMAKE_CXX_STANDARD.rst2
-rw-r--r--Help/variable/CMAKE_CXX_STANDARD_REQUIRED.rst2
-rw-r--r--Help/variable/CMAKE_C_COMPILE_FEATURES.rst4
-rw-r--r--Help/variable/CMAKE_C_EXTENSIONS.rst2
-rw-r--r--Help/variable/CMAKE_C_STANDARD.rst2
-rw-r--r--Help/variable/CMAKE_C_STANDARD_REQUIRED.rst2
-rw-r--r--Help/variable/CMAKE_DEBUG_POSTFIX.rst4
-rw-r--r--Help/variable/CMAKE_DEBUG_TARGET_PROPERTIES.rst6
-rw-r--r--Help/variable/CMAKE_DISABLE_FIND_PACKAGE_PackageName.rst9
-rw-r--r--Help/variable/CMAKE_DL_LIBS.rst6
-rw-r--r--Help/variable/CMAKE_EDIT_COMMAND.rst6
-rw-r--r--Help/variable/CMAKE_ERROR_DEPRECATED.rst4
-rw-r--r--Help/variable/CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION.rst5
-rw-r--r--Help/variable/CMAKE_EXECUTABLE_SUFFIX.rst4
-rw-r--r--Help/variable/CMAKE_EXE_LINKER_FLAGS_CONFIG.rst2
-rw-r--r--Help/variable/CMAKE_EXTRA_GENERATOR.rst9
-rw-r--r--Help/variable/CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES.rst2
-rw-r--r--Help/variable/CMAKE_FIND_LIBRARY_PREFIXES.rst6
-rw-r--r--Help/variable/CMAKE_FIND_LIBRARY_SUFFIXES.rst6
-rw-r--r--Help/variable/CMAKE_FIND_NO_INSTALL_PREFIX.rst6
-rw-r--r--Help/variable/CMAKE_FIND_PACKAGE_WARN_NO_MODULE.rst18
-rw-r--r--Help/variable/CMAKE_FIND_ROOT_PATH.rst4
-rw-r--r--Help/variable/CMAKE_Fortran_FORMAT.rst6
-rw-r--r--Help/variable/CMAKE_Fortran_MODDIR_DEFAULT.rst6
-rw-r--r--Help/variable/CMAKE_Fortran_MODDIR_FLAG.rst2
-rw-r--r--Help/variable/CMAKE_Fortran_MODOUT_FLAG.rst2
-rw-r--r--Help/variable/CMAKE_Fortran_MODULE_DIRECTORY.rst2
-rw-r--r--Help/variable/CMAKE_GENERATOR.rst4
-rw-r--r--Help/variable/CMAKE_GENERATOR_PLATFORM.rst4
-rw-r--r--Help/variable/CMAKE_GENERATOR_TOOLSET.rst4
-rw-r--r--Help/variable/CMAKE_GNUtoMS.rst6
-rw-r--r--Help/variable/CMAKE_HOST_APPLE.rst4
-rw-r--r--Help/variable/CMAKE_HOST_SYSTEM_NAME.rst2
-rw-r--r--Help/variable/CMAKE_HOST_SYSTEM_PROCESSOR.rst4
-rw-r--r--Help/variable/CMAKE_HOST_SYSTEM_VERSION.rst2
-rw-r--r--Help/variable/CMAKE_HOST_UNIX.rst4
-rw-r--r--Help/variable/CMAKE_HOST_WIN32.rst4
-rw-r--r--Help/variable/CMAKE_IMPORT_LIBRARY_PREFIX.rst2
-rw-r--r--Help/variable/CMAKE_IMPORT_LIBRARY_SUFFIX.rst2
-rw-r--r--Help/variable/CMAKE_INCLUDE_CURRENT_DIR.rst8
-rw-r--r--Help/variable/CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE.rst10
-rw-r--r--Help/variable/CMAKE_INCLUDE_DIRECTORIES_BEFORE.rst7
-rw-r--r--Help/variable/CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE.rst4
-rw-r--r--Help/variable/CMAKE_INSTALL_DEFAULT_COMPONENT_NAME.rst8
-rw-r--r--Help/variable/CMAKE_INSTALL_NAME_DIR.rst6
-rw-r--r--Help/variable/CMAKE_INSTALL_PREFIX.rst25
-rw-r--r--Help/variable/CMAKE_INSTALL_RPATH.rst2
-rw-r--r--Help/variable/CMAKE_INSTALL_RPATH_USE_LINK_PATH.rst6
-rw-r--r--Help/variable/CMAKE_LANG_ARCHIVE_APPEND.rst7
-rw-r--r--Help/variable/CMAKE_LANG_ARCHIVE_CREATE.rst7
-rw-r--r--Help/variable/CMAKE_LANG_ARCHIVE_FINISH.rst7
-rw-r--r--Help/variable/CMAKE_LANG_COMPILER.rst4
-rw-r--r--Help/variable/CMAKE_LANG_COMPILER_EXTERNAL_TOOLCHAIN.rst6
-rw-r--r--Help/variable/CMAKE_LANG_COMPILER_LOADED.rst4
-rw-r--r--Help/variable/CMAKE_LANG_COMPILE_OBJECT.rst2
-rw-r--r--Help/variable/CMAKE_LANG_CREATE_SHARED_LIBRARY.rst2
-rw-r--r--Help/variable/CMAKE_LANG_CREATE_SHARED_MODULE.rst2
-rw-r--r--Help/variable/CMAKE_LANG_CREATE_STATIC_LIBRARY.rst2
-rw-r--r--Help/variable/CMAKE_LANG_FLAGS.rst2
-rw-r--r--Help/variable/CMAKE_LANG_FLAGS_DEBUG.rst4
-rw-r--r--Help/variable/CMAKE_LANG_FLAGS_MINSIZEREL.rst6
-rw-r--r--Help/variable/CMAKE_LANG_FLAGS_RELEASE.rst4
-rw-r--r--Help/variable/CMAKE_LANG_FLAGS_RELWITHDEBINFO.rst6
-rw-r--r--Help/variable/CMAKE_LANG_GHS_KERNEL_FLAGS_DEBUG.rst4
-rw-r--r--Help/variable/CMAKE_LANG_GHS_KERNEL_FLAGS_MINSIZEREL.rst6
-rw-r--r--Help/variable/CMAKE_LANG_GHS_KERNEL_FLAGS_RELEASE.rst4
-rw-r--r--Help/variable/CMAKE_LANG_GHS_KERNEL_FLAGS_RELWITHDEBINFO.rst6
-rw-r--r--Help/variable/CMAKE_LANG_IMPLICIT_INCLUDE_DIRECTORIES.rst2
-rw-r--r--Help/variable/CMAKE_LANG_IMPLICIT_LINK_DIRECTORIES.rst8
-rw-r--r--Help/variable/CMAKE_LANG_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES.rst2
-rw-r--r--Help/variable/CMAKE_LANG_IMPLICIT_LINK_LIBRARIES.rst2
-rw-r--r--Help/variable/CMAKE_LANG_LIBRARY_ARCHITECTURE.rst8
-rw-r--r--Help/variable/CMAKE_LANG_LINKER_PREFERENCE.rst4
-rw-r--r--Help/variable/CMAKE_LANG_LINKER_PREFERENCE_PROPAGATES.rst2
-rw-r--r--Help/variable/CMAKE_LANG_OUTPUT_EXTENSION.rst4
-rw-r--r--Help/variable/CMAKE_LANG_SIMULATE_ID.rst4
-rw-r--r--Help/variable/CMAKE_LANG_SIMULATE_VERSION.rst4
-rw-r--r--Help/variable/CMAKE_LANG_SIZEOF_DATA_PTR.rst4
-rw-r--r--Help/variable/CMAKE_LIBRARY_ARCHITECTURE.rst4
-rw-r--r--Help/variable/CMAKE_LIBRARY_ARCHITECTURE_REGEX.rst4
-rw-r--r--Help/variable/CMAKE_LIBRARY_PATH_FLAG.rst2
-rw-r--r--Help/variable/CMAKE_LINK_DEF_FILE_FLAG.rst4
-rw-r--r--Help/variable/CMAKE_LINK_DEPENDS_NO_SHARED.rst2
-rw-r--r--Help/variable/CMAKE_LINK_INTERFACE_LIBRARIES.rst4
-rw-r--r--Help/variable/CMAKE_LINK_LIBRARY_FLAG.rst2
-rw-r--r--Help/variable/CMAKE_LINK_LIBRARY_SUFFIX.rst2
-rw-r--r--Help/variable/CMAKE_LINK_SEARCH_END_STATIC.rst19
-rw-r--r--Help/variable/CMAKE_LINK_SEARCH_START_STATIC.rst20
-rw-r--r--Help/variable/CMAKE_MACOSX_BUNDLE.rst6
-rw-r--r--Help/variable/CMAKE_MAKE_PROGRAM.rst10
-rw-r--r--Help/variable/CMAKE_MAP_IMPORTED_CONFIG_CONFIG.rst8
-rw-r--r--Help/variable/CMAKE_MFC_FLAG.rst6
-rw-r--r--Help/variable/CMAKE_MINIMUM_REQUIRED_VERSION.rst6
-rw-r--r--Help/variable/CMAKE_MODULE_LINKER_FLAGS_CONFIG.rst2
-rw-r--r--Help/variable/CMAKE_NOT_USING_CONFIG_FLAGS.rst4
-rw-r--r--Help/variable/CMAKE_NO_SYSTEM_FROM_IMPORTED.rst4
-rw-r--r--Help/variable/CMAKE_PARENT_LIST_FILE.rst8
-rw-r--r--Help/variable/CMAKE_POLICY_DEFAULT_CMPNNNN.rst19
-rw-r--r--Help/variable/CMAKE_POSITION_INDEPENDENT_CODE.rst9
-rw-r--r--Help/variable/CMAKE_PROJECT_NAME.rst2
-rw-r--r--Help/variable/CMAKE_ROOT.rst4
-rw-r--r--Help/variable/CMAKE_SCRIPT_MODE_FILE.rst9
-rw-r--r--Help/variable/CMAKE_SHARED_LIBRARY_PREFIX.rst4
-rw-r--r--Help/variable/CMAKE_SHARED_LIBRARY_SUFFIX.rst4
-rw-r--r--Help/variable/CMAKE_SHARED_LINKER_FLAGS_CONFIG.rst2
-rw-r--r--Help/variable/CMAKE_SHARED_MODULE_PREFIX.rst2
-rw-r--r--Help/variable/CMAKE_SHARED_MODULE_SUFFIX.rst2
-rw-r--r--Help/variable/CMAKE_SIZEOF_VOID_P.rst6
-rw-r--r--Help/variable/CMAKE_SKIP_INSTALL_ALL_DEPENDENCY.rst12
-rw-r--r--Help/variable/CMAKE_SKIP_INSTALL_RPATH.rst2
-rw-r--r--Help/variable/CMAKE_SKIP_INSTALL_RULES.rst5
-rw-r--r--Help/variable/CMAKE_SKIP_RPATH.rst4
-rw-r--r--Help/variable/CMAKE_SOURCE_DIR.rst2
-rw-r--r--Help/variable/CMAKE_STAGING_PREFIX.rst11
-rw-r--r--Help/variable/CMAKE_STATIC_LIBRARY_PREFIX.rst4
-rw-r--r--Help/variable/CMAKE_STATIC_LIBRARY_SUFFIX.rst4
-rw-r--r--Help/variable/CMAKE_STATIC_LINKER_FLAGS_CONFIG.rst2
-rw-r--r--Help/variable/CMAKE_SYSTEM.rst2
-rw-r--r--Help/variable/CMAKE_SYSTEM_NAME.rst6
-rw-r--r--Help/variable/CMAKE_SYSTEM_PROCESSOR.rst2
-rw-r--r--Help/variable/CMAKE_SYSTEM_VERSION.rst2
-rw-r--r--Help/variable/CMAKE_TOOLCHAIN_FILE.rst6
-rw-r--r--Help/variable/CMAKE_TRY_COMPILE_CONFIGURATION.rst7
-rw-r--r--Help/variable/CMAKE_USER_MAKE_RULES_OVERRIDE.rst20
-rw-r--r--Help/variable/CMAKE_USER_MAKE_RULES_OVERRIDE_LANG.rst7
-rw-r--r--Help/variable/CMAKE_VERBOSE_MAKEFILE.rst2
-rw-r--r--Help/variable/CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD.rst8
-rw-r--r--Help/variable/CMAKE_VS_INTEL_Fortran_PROJECT_VERSION.rst4
-rw-r--r--Help/variable/CMAKE_VS_PLATFORM_TOOLSET.rst2
-rw-r--r--Help/variable/CMAKE_WARN_DEPRECATED.rst4
-rw-r--r--Help/variable/CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION.rst7
-rw-r--r--Help/variable/CMAKE_WIN32_EXECUTABLE.rst6
-rw-r--r--Help/variable/CMAKE_XCODE_ATTRIBUTE_an-attribute.rst4
-rw-r--r--Help/variable/CMAKE_XCODE_PLATFORM_TOOLSET.rst6
-rw-r--r--Help/variable/CPACK_ABSOLUTE_DESTINATION_FILES.rst6
-rw-r--r--Help/variable/CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY.rst6
-rw-r--r--Help/variable/CPACK_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION.rst9
-rw-r--r--Help/variable/CPACK_INCLUDE_TOPLEVEL_DIRECTORY.rst11
-rw-r--r--Help/variable/CPACK_INSTALL_SCRIPT.rst2
-rw-r--r--Help/variable/CPACK_PACKAGING_INSTALL_PREFIX.rst12
-rw-r--r--Help/variable/CPACK_SET_DESTDIR.rst31
-rw-r--r--Help/variable/CPACK_WARN_ON_ABSOLUTE_INSTALL_DESTINATION.rst7
-rw-r--r--Help/variable/CTEST_COVERAGE_COMMAND.rst20
-rw-r--r--Help/variable/CTEST_MEMORYCHECK_TYPE.rst5
-rw-r--r--Help/variable/CYGWIN.rst4
-rw-r--r--Help/variable/ENV.rst4
-rw-r--r--Help/variable/EXECUTABLE_OUTPUT_PATH.rst4
-rw-r--r--Help/variable/LIBRARY_OUTPUT_PATH.rst8
-rw-r--r--Help/variable/MINGW.rst4
-rw-r--r--Help/variable/MSVC.rst4
-rw-r--r--Help/variable/MSVC10.rst4
-rw-r--r--Help/variable/MSVC11.rst4
-rw-r--r--Help/variable/MSVC12.rst4
-rw-r--r--Help/variable/MSVC14.rst4
-rw-r--r--Help/variable/MSVC60.rst4
-rw-r--r--Help/variable/MSVC70.rst4
-rw-r--r--Help/variable/MSVC71.rst4
-rw-r--r--Help/variable/MSVC80.rst4
-rw-r--r--Help/variable/MSVC90.rst4
-rw-r--r--Help/variable/MSVC_IDE.rst4
-rw-r--r--Help/variable/UNIX.rst6
-rw-r--r--Help/variable/WIN32.rst4
-rw-r--r--Help/variable/XCODE_VERSION.rst4
-rw-r--r--Modules/CMakeFortranCompiler.cmake.in1
-rw-r--r--Modules/CPackRPM.cmake73
-rw-r--r--Modules/Compiler/Cray-DetermineCompiler.cmake2
-rw-r--r--Modules/Compiler/GNU-DetermineCompiler.cmake4
-rw-r--r--Modules/DartConfiguration.tcl.in1
-rw-r--r--Modules/ExternalProject.cmake8
-rw-r--r--Modules/FindBoost.cmake6
-rw-r--r--Modules/FindJava.cmake94
-rw-r--r--Modules/FindMPI.cmake8
-rw-r--r--Modules/FindOpenSSL.cmake142
-rw-r--r--Modules/FindPkgConfig.cmake12
-rw-r--r--Modules/FindProtobuf.cmake17
-rw-r--r--Modules/FindTIFF.cmake14
-rw-r--r--Modules/FindXercesC.cmake16
-rw-r--r--Modules/GetPrerequisites.cmake38
-rw-r--r--Modules/Platform/ARTOS-GNU-C.cmake9
-rw-r--r--Modules/Platform/ARTOS.cmake17
-rw-r--r--Modules/Platform/HP-UX.cmake17
-rw-r--r--Modules/Platform/SunOS.cmake8
-rw-r--r--Modules/UseJava.cmake88
-rw-r--r--Source/CMakeLists.txt1
-rw-r--r--Source/CMakeVersion.cmake2
-rw-r--r--Source/CTest/cmCTestCoverageHandler.cxx33
-rw-r--r--Source/CTest/cmCTestCoverageHandler.h2
-rw-r--r--Source/QtDialog/Info.plist.in2
-rw-r--r--Source/cmCTest.cxx5
-rw-r--r--Source/cmCommonTargetGenerator.cxx130
-rw-r--r--Source/cmCommonTargetGenerator.h9
-rw-r--r--Source/cmComputeLinkDepends.cxx17
-rw-r--r--Source/cmComputeLinkDepends.h6
-rw-r--r--Source/cmComputeLinkInformation.cxx98
-rw-r--r--Source/cmComputeLinkInformation.h6
-rw-r--r--Source/cmConditionEvaluator.cxx26
-rw-r--r--Source/cmConditionEvaluator.h1
-rw-r--r--Source/cmCoreTryCompile.cxx10
-rw-r--r--Source/cmCurl.cxx2
-rw-r--r--Source/cmDependsFortran.cxx13
-rw-r--r--Source/cmDependsFortran.h3
-rw-r--r--Source/cmExportBuildFileGenerator.cxx10
-rw-r--r--Source/cmExportBuildFileGenerator.h3
-rw-r--r--Source/cmExportFileGenerator.cxx17
-rw-r--r--Source/cmExportFileGenerator.h4
-rw-r--r--Source/cmExportInstallFileGenerator.cxx14
-rw-r--r--Source/cmExportInstallFileGenerator.h3
-rw-r--r--Source/cmExportLibraryDependenciesCommand.cxx8
-rw-r--r--Source/cmExportTryCompileFileGenerator.cxx4
-rw-r--r--Source/cmExportTryCompileFileGenerator.h6
-rw-r--r--Source/cmFileCommand.cxx7
-rw-r--r--Source/cmGeneratorExpressionEvaluationFile.cxx40
-rw-r--r--Source/cmGeneratorExpressionEvaluationFile.h15
-rw-r--r--Source/cmGeneratorExpressionNode.cxx58
-rw-r--r--Source/cmGeneratorTarget.cxx2009
-rw-r--r--Source/cmGeneratorTarget.h197
-rw-r--r--Source/cmGetDirectoryPropertyCommand.cxx7
-rw-r--r--Source/cmGetFilenameComponentCommand.cxx4
-rw-r--r--Source/cmGetPropertyCommand.cxx9
-rw-r--r--Source/cmGhsMultiTargetGenerator.cxx3
-rw-r--r--Source/cmGlobalGenerator.cxx229
-rw-r--r--Source/cmGlobalGenerator.h35
-rw-r--r--Source/cmGlobalJOMMakefileGenerator.cxx28
-rw-r--r--Source/cmGlobalJOMMakefileGenerator.h3
-rw-r--r--Source/cmGlobalNMakeMakefileGenerator.cxx28
-rw-r--r--Source/cmGlobalNMakeMakefileGenerator.h3
-rw-r--r--Source/cmGlobalNinjaGenerator.cxx49
-rw-r--r--Source/cmGlobalNinjaGenerator.h8
-rw-r--r--Source/cmGlobalUnixMakefileGenerator3.cxx10
-rw-r--r--Source/cmGlobalVisualStudio10Generator.cxx11
-rw-r--r--Source/cmGlobalVisualStudio10Generator.h2
-rw-r--r--Source/cmGlobalVisualStudio8Generator.cxx14
-rw-r--r--Source/cmGlobalVisualStudio8Generator.h2
-rw-r--r--Source/cmGlobalVisualStudioGenerator.cxx26
-rw-r--r--Source/cmGlobalVisualStudioGenerator.h2
-rw-r--r--Source/cmGlobalXCodeGenerator.cxx57
-rw-r--r--Source/cmGlobalXCodeGenerator.h1
-rw-r--r--Source/cmInstallCommand.cxx9
-rw-r--r--Source/cmInstallGenerator.h2
-rw-r--r--Source/cmInstallTargetGenerator.cxx84
-rw-r--r--Source/cmInstallTargetGenerator.h14
-rw-r--r--Source/cmLinkItem.h59
-rw-r--r--Source/cmLinkedTree.h6
-rw-r--r--Source/cmLocalGenerator.cxx74
-rw-r--r--Source/cmLocalGenerator.h2
-rw-r--r--Source/cmLocalNinjaGenerator.cxx14
-rw-r--r--Source/cmLocalUnixMakefileGenerator3.cxx3
-rw-r--r--Source/cmLocalVisualStudio6Generator.cxx43
-rw-r--r--Source/cmLocalVisualStudio7Generator.cxx31
-rw-r--r--Source/cmMakefile.cxx185
-rw-r--r--Source/cmMakefile.h48
-rw-r--r--Source/cmMakefileExecutableTargetGenerator.cxx10
-rw-r--r--Source/cmMakefileLibraryTargetGenerator.cxx24
-rw-r--r--Source/cmMakefileTargetGenerator.cxx63
-rw-r--r--Source/cmMakefileTargetGenerator.h1
-rw-r--r--Source/cmNinjaNormalTargetGenerator.cxx19
-rw-r--r--Source/cmNinjaTargetGenerator.cxx20
-rw-r--r--Source/cmOSXBundleGenerator.cxx14
-rw-r--r--Source/cmOrderDirectories.cxx8
-rw-r--r--Source/cmOrderDirectories.h6
-rw-r--r--Source/cmPolicies.h3
-rw-r--r--Source/cmQtAutoGenerators.cxx23
-rw-r--r--Source/cmScriptGenerator.h3
-rw-r--r--Source/cmSetPropertyCommand.cxx10
-rw-r--r--Source/cmState.cxx171
-rw-r--r--Source/cmState.h15
-rw-r--r--Source/cmSystemTools.cxx19
-rw-r--r--Source/cmTarget.cxx2273
-rw-r--r--Source/cmTarget.h230
-rw-r--r--Source/cmTargetIncludeDirectoriesCommand.cxx20
-rw-r--r--Source/cmVisualStudio10TargetGenerator.cxx18
-rw-r--r--Source/cmXCodeObject.cxx6
-rw-r--r--Source/cmake.cxx33
-rw-r--r--Source/cmcmd.cxx19
-rw-r--r--Source/kwsys/CMakeLists.txt6
-rw-r--r--Source/kwsys/CTestCustom.cmake.in15
-rw-r--r--Source/kwsys/EncodingC.c14
-rw-r--r--Source/kwsys/Process.h.in131
-rw-r--r--Source/kwsys/ProcessUNIX.c357
-rw-r--r--Source/kwsys/ProcessWin32.c462
-rw-r--r--Source/kwsys/SystemTools.cxx18
-rw-r--r--Source/kwsys/testProcess.c267
-rw-r--r--Source/kwsys/testSystemTools.cxx22
-rw-r--r--Tests/BuildDepends/CMakeLists.txt2
-rw-r--r--Tests/CMakeLists.txt25
-rw-r--r--Tests/CMakeOnly/Test.cmake.in6
-rw-r--r--Tests/CTestTest2/test.cmake.in13
-rw-r--r--Tests/ExportImport/Export/CMakeLists.txt17
-rw-r--r--Tests/ExportImport/Export/testExe4.c24
-rw-r--r--Tests/ExportImport/Import/A/CMakeLists.txt12
-rw-r--r--Tests/ExportImport/Import/A/imp_testExe1.c3
-rw-r--r--Tests/FindOpenSSL/CMakeLists.txt9
-rw-r--r--Tests/FindOpenSSL/rand/CMakeLists.txt14
-rw-r--r--Tests/FindOpenSSL/rand/main.cc22
-rw-r--r--Tests/FortranC/Flags.cmake.in6
-rw-r--r--Tests/IncludeDirectories/SystemIncludeDirectories/CMakeLists.txt10
-rw-r--r--Tests/Java/CMakeLists.txt4
-rw-r--r--Tests/RunCMake/CMP0064/CMP0064-NEW.cmake5
-rw-r--r--Tests/RunCMake/CMP0064/CMP0064-OLD.cmake7
-rw-r--r--Tests/RunCMake/CMP0064/CMP0064-WARN.cmake7
-rw-r--r--Tests/RunCMake/CMP0064/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/CMP0064/RunCMakeTest.cmake5
-rw-r--r--Tests/RunCMake/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/CPack/CMakeLists.txt2
-rw-r--r--Tests/RunCMake/CPack/DEB/DEPENDENCIES-ExpectedFiles.cmake14
-rw-r--r--Tests/RunCMake/CPack/DEB/DEPENDENCIES-VerifyResult.cmake15
-rw-r--r--Tests/RunCMake/CPack/DEB/DEPENDENCIES-specifics.cmake15
-rw-r--r--Tests/RunCMake/CPack/DEB/Helpers.cmake10
-rw-r--r--Tests/RunCMake/CPack/DEPENDENCIES.cmake18
-rw-r--r--Tests/RunCMake/CPack/RPM/DEPENDENCIES-ExpectedFiles.cmake13
-rw-r--r--Tests/RunCMake/CPack/RPM/DEPENDENCIES-VerifyResult.cmake45
-rw-r--r--Tests/RunCMake/CPack/RPM/DEPENDENCIES-specifics.cmake22
-rw-r--r--Tests/RunCMake/CPack/RunCMakeTest.cmake1
-rw-r--r--Tests/RunCMake/CPack/VerifyResult.cmake2
-rw-r--r--Tests/RunCMake/CompilerNotFound/BadCompilerC-stderr-JOM.txt17
-rw-r--r--Tests/RunCMake/CompilerNotFound/BadCompilerC-stderr-NMake.txt17
-rw-r--r--Tests/RunCMake/CompilerNotFound/BadCompilerCXX-stderr-JOM.txt17
-rw-r--r--Tests/RunCMake/CompilerNotFound/BadCompilerCXX-stderr-NMake.txt17
-rw-r--r--Tests/RunCMake/CompilerNotFound/BadCompilerCandCXX-stderr-JOM.txt35
-rw-r--r--Tests/RunCMake/CompilerNotFound/BadCompilerCandCXX-stderr-NMake.txt35
-rw-r--r--Tests/RunCMake/CompilerNotFound/RunCMakeTest.cmake14
-rw-r--r--Tests/RunCMake/GeneratorExpression/ImportedTarget-TARGET_PDB_FILE-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorExpression/ImportedTarget-TARGET_PDB_FILE-stderr.txt8
-rw-r--r--Tests/RunCMake/GeneratorExpression/ImportedTarget-TARGET_PDB_FILE.cmake2
-rw-r--r--Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake2
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_FILE-recursion-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_FILE-recursion-stderr.txt4
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_FILE-recursion.cmake3
-rw-r--r--Tests/RunCMake/PolicyScope/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/PolicyScope/RunCMakeTest.cmake4
-rw-r--r--Tests/RunCMake/PolicyScope/dir-in-macro-generate-time-result.txt1
-rw-r--r--Tests/RunCMake/PolicyScope/dir-in-macro-generate-time-stderr.txt5
-rw-r--r--Tests/RunCMake/PolicyScope/dir-in-macro-generate-time.cmake2
-rw-r--r--Tests/RunCMake/PolicyScope/dir-in-macro-include.cmake6
-rw-r--r--Tests/RunCMake/PolicyScope/dir1/CMakeLists.txt5
-rw-r--r--Tests/RunCMake/PolicyScope/dir1/foo.cpp5
-rw-r--r--Tests/RunCMake/PolicyScope/parent-dir-generate-time-result.txt1
-rw-r--r--Tests/RunCMake/PolicyScope/parent-dir-generate-time.cmake7
-rw-r--r--Tests/RunCMake/add_subdirectory/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/add_subdirectory/DoesNotExist-result.txt1
-rw-r--r--Tests/RunCMake/add_subdirectory/DoesNotExist-stderr.txt5
-rw-r--r--Tests/RunCMake/add_subdirectory/DoesNotExist.cmake1
-rw-r--r--Tests/RunCMake/add_subdirectory/Missing-result.txt1
-rw-r--r--Tests/RunCMake/add_subdirectory/Missing-stderr.txt8
-rw-r--r--Tests/RunCMake/add_subdirectory/Missing.cmake1
-rw-r--r--Tests/RunCMake/add_subdirectory/Missing/Missing.txt0
-rw-r--r--Tests/RunCMake/add_subdirectory/RunCMakeTest.cmake4
-rw-r--r--Tests/RunCMake/get_filename_component/CMakeLists.txt2
-rw-r--r--Tests/RunCMake/get_filename_component/KnownComponents.cmake77
-rw-r--r--Tests/RunCMake/if/RunCMakeTest.cmake3
-rw-r--r--Tests/RunCMake/if/TestNameThatDoesNotExist-stdout.txt1
-rw-r--r--Tests/RunCMake/if/TestNameThatDoesNotExist.cmake6
-rw-r--r--Tests/RunCMake/if/TestNameThatExists-stdout.txt1
-rw-r--r--Tests/RunCMake/if/TestNameThatExists.cmake7
-rw-r--r--Tests/RunCMake/set_property/LINK_SEARCH_STATIC.cmake73
-rw-r--r--Tests/RunCMake/set_property/LinkStatic.c5
-rw-r--r--Tests/RunCMake/set_property/RunCMakeTest.cmake1
-rw-r--r--Tests/RunCMake/target_link_libraries/RunCMakeTest.cmake1
-rw-r--r--Tests/RunCMake/target_link_libraries/SharedDepNotTarget.cmake10
-rw-r--r--Utilities/Release/dash2win64_cygwin.cmake1
-rw-r--r--Utilities/Release/dash2win64_release.cmake1
-rw-r--r--Utilities/Release/dashmacmini2_release.cmake1
-rw-r--r--Utilities/Release/dashmacmini5_release.cmake1
-rw-r--r--Utilities/Release/linux64_release.cmake1
-rw-r--r--Utilities/Release/magrathea_release.cmake1
-rw-r--r--Utilities/cmcurl/CMake/CurlCheckCSourceCompiles.cmake71
-rw-r--r--Utilities/cmcurl/CMake/CurlCheckCSourceRuns.cmake83
-rw-r--r--Utilities/cmcurl/CMake/CurlTests.c316
-rw-r--r--Utilities/cmcurl/CMake/FindGSS.cmake289
-rw-r--r--Utilities/cmcurl/CMake/Macros.cmake8
-rw-r--r--Utilities/cmcurl/CMake/OtherTests.cmake200
-rw-r--r--Utilities/cmcurl/CMake/Platforms/WindowsCache.cmake2
-rw-r--r--Utilities/cmcurl/CMakeLists.txt508
-rw-r--r--Utilities/cmcurl/COPYING2
-rw-r--r--Utilities/cmcurl/README-CMake.txt8
-rw-r--r--Utilities/cmcurl/include/curl/curl.h94
-rw-r--r--Utilities/cmcurl/include/curl/curlver.h18
-rw-r--r--Utilities/cmcurl/include/curl/mprintf.h9
-rw-r--r--Utilities/cmcurl/include/curl/multi.h38
-rw-r--r--Utilities/cmcurl/include/curl/typecheck-gcc.h2
-rw-r--r--Utilities/cmcurl/lib/CMakeLists.txt28
-rw-r--r--Utilities/cmcurl/lib/Makefile.inc86
-rw-r--r--Utilities/cmcurl/lib/amigaos.c4
-rw-r--r--Utilities/cmcurl/lib/asyn-ares.c37
-rw-r--r--Utilities/cmcurl/lib/asyn-thread.c45
-rw-r--r--Utilities/cmcurl/lib/base64.c23
-rw-r--r--Utilities/cmcurl/lib/bundles.c110
-rw-r--r--Utilities/cmcurl/lib/conncache.c179
-rw-r--r--Utilities/cmcurl/lib/conncache.h21
-rw-r--r--Utilities/cmcurl/lib/connect.c227
-rw-r--r--Utilities/cmcurl/lib/connect.h2
-rw-r--r--Utilities/cmcurl/lib/cookie.c208
-rw-r--r--Utilities/cmcurl/lib/curl_addrinfo.c59
-rw-r--r--Utilities/cmcurl/lib/curl_addrinfo.h4
-rw-r--r--Utilities/cmcurl/lib/curl_config.h.cmake12
-rw-r--r--Utilities/cmcurl/lib/curl_des.c63
-rw-r--r--Utilities/cmcurl/lib/curl_des.h (renamed from Utilities/cmcurl/lib/bundles.h)29
-rw-r--r--Utilities/cmcurl/lib/curl_endian.c236
-rw-r--r--Utilities/cmcurl/lib/curl_endian.h70
-rw-r--r--Utilities/cmcurl/lib/curl_fnmatch.c7
-rw-r--r--Utilities/cmcurl/lib/curl_gssapi.c53
-rw-r--r--Utilities/cmcurl/lib/curl_gssapi.h19
-rw-r--r--Utilities/cmcurl/lib/curl_md4.h12
-rw-r--r--Utilities/cmcurl/lib/curl_memory.h3
-rw-r--r--Utilities/cmcurl/lib/curl_memrchr.c8
-rw-r--r--Utilities/cmcurl/lib/curl_multibyte.c18
-rw-r--r--Utilities/cmcurl/lib/curl_multibyte.h12
-rw-r--r--Utilities/cmcurl/lib/curl_ntlm.c79
-rw-r--r--Utilities/cmcurl/lib/curl_ntlm.h10
-rw-r--r--Utilities/cmcurl/lib/curl_ntlm_core.c292
-rw-r--r--Utilities/cmcurl/lib/curl_ntlm_core.h59
-rw-r--r--Utilities/cmcurl/lib/curl_ntlm_msgs.c461
-rw-r--r--Utilities/cmcurl/lib/curl_ntlm_msgs.h34
-rw-r--r--Utilities/cmcurl/lib/curl_ntlm_wb.c46
-rw-r--r--Utilities/cmcurl/lib/curl_ntlm_wb.h7
-rw-r--r--Utilities/cmcurl/lib/curl_printf.h56
-rw-r--r--Utilities/cmcurl/lib/curl_rtmp.c27
-rw-r--r--Utilities/cmcurl/lib/curl_sasl.c1158
-rw-r--r--Utilities/cmcurl/lib/curl_sasl.h164
-rw-r--r--Utilities/cmcurl/lib/curl_sasl_gssapi.c392
-rw-r--r--Utilities/cmcurl/lib/curl_sasl_sspi.c861
-rw-r--r--Utilities/cmcurl/lib/curl_sec.h4
-rw-r--r--Utilities/cmcurl/lib/curl_setup.h53
-rw-r--r--Utilities/cmcurl/lib/curl_sspi.c30
-rw-r--r--Utilities/cmcurl/lib/curl_sspi.h191
-rw-r--r--Utilities/cmcurl/lib/curl_threads.c15
-rw-r--r--Utilities/cmcurl/lib/curl_threads.h9
-rw-r--r--Utilities/cmcurl/lib/curlx.h5
-rw-r--r--Utilities/cmcurl/lib/dict.c16
-rw-r--r--Utilities/cmcurl/lib/easy.c180
-rw-r--r--Utilities/cmcurl/lib/escape.c28
-rw-r--r--Utilities/cmcurl/lib/file.c63
-rw-r--r--Utilities/cmcurl/lib/fileinfo.c6
-rw-r--r--Utilities/cmcurl/lib/formdata.c127
-rw-r--r--Utilities/cmcurl/lib/ftp.c305
-rw-r--r--Utilities/cmcurl/lib/ftp.h11
-rw-r--r--Utilities/cmcurl/lib/ftplistparser.c57
-rw-r--r--Utilities/cmcurl/lib/getinfo.c55
-rw-r--r--Utilities/cmcurl/lib/gopher.c16
-rw-r--r--Utilities/cmcurl/lib/hash.c72
-rw-r--r--Utilities/cmcurl/lib/hash.h10
-rw-r--r--Utilities/cmcurl/lib/hmac.c6
-rw-r--r--Utilities/cmcurl/lib/hostasyn.c24
-rw-r--r--Utilities/cmcurl/lib/hostcheck.c7
-rw-r--r--Utilities/cmcurl/lib/hostip.c287
-rw-r--r--Utilities/cmcurl/lib/hostip.h22
-rw-r--r--Utilities/cmcurl/lib/hostip4.c15
-rw-r--r--Utilities/cmcurl/lib/hostip6.c17
-rw-r--r--Utilities/cmcurl/lib/hostsyn.c6
-rw-r--r--Utilities/cmcurl/lib/http.c378
-rw-r--r--Utilities/cmcurl/lib/http.h64
-rw-r--r--Utilities/cmcurl/lib/http2.c1184
-rw-r--r--Utilities/cmcurl/lib/http2.h17
-rw-r--r--Utilities/cmcurl/lib/http_chunks.c12
-rw-r--r--Utilities/cmcurl/lib/http_digest.c549
-rw-r--r--Utilities/cmcurl/lib/http_digest.h21
-rw-r--r--Utilities/cmcurl/lib/http_negotiate.c163
-rw-r--r--Utilities/cmcurl/lib/http_negotiate.h6
-rw-r--r--Utilities/cmcurl/lib/http_negotiate_sspi.c118
-rw-r--r--Utilities/cmcurl/lib/http_proxy.c64
-rw-r--r--Utilities/cmcurl/lib/http_proxy.h7
-rw-r--r--Utilities/cmcurl/lib/idn_win32.c29
-rw-r--r--Utilities/cmcurl/lib/if2ip.c87
-rw-r--r--Utilities/cmcurl/lib/if2ip.h13
-rw-r--r--Utilities/cmcurl/lib/imap.c989
-rw-r--r--Utilities/cmcurl/lib/imap.h23
-rw-r--r--Utilities/cmcurl/lib/inet_ntop.c3
-rw-r--r--Utilities/cmcurl/lib/inet_ntop.h4
-rw-r--r--Utilities/cmcurl/lib/krb5.c36
-rw-r--r--Utilities/cmcurl/lib/ldap.c622
-rw-r--r--Utilities/cmcurl/lib/md4.c502
-rw-r--r--Utilities/cmcurl/lib/md5.c579
-rw-r--r--Utilities/cmcurl/lib/memdebug.c39
-rw-r--r--Utilities/cmcurl/lib/memdebug.h20
-rw-r--r--Utilities/cmcurl/lib/multi.c819
-rw-r--r--Utilities/cmcurl/lib/multihandle.h52
-rw-r--r--Utilities/cmcurl/lib/multiif.h22
-rw-r--r--Utilities/cmcurl/lib/netrc.c20
-rw-r--r--Utilities/cmcurl/lib/non-ascii.c55
-rw-r--r--Utilities/cmcurl/lib/nwlib.c8
-rw-r--r--Utilities/cmcurl/lib/openldap.c142
-rw-r--r--Utilities/cmcurl/lib/parsedate.c2
-rw-r--r--Utilities/cmcurl/lib/pingpong.c56
-rw-r--r--Utilities/cmcurl/lib/pipeline.c119
-rw-r--r--Utilities/cmcurl/lib/pipeline.h12
-rw-r--r--Utilities/cmcurl/lib/pop3.c972
-rw-r--r--Utilities/cmcurl/lib/pop3.h23
-rw-r--r--Utilities/cmcurl/lib/progress.c6
-rw-r--r--Utilities/cmcurl/lib/rtsp.c24
-rw-r--r--Utilities/cmcurl/lib/security.c187
-rw-r--r--Utilities/cmcurl/lib/select.c12
-rw-r--r--Utilities/cmcurl/lib/sendf.c218
-rw-r--r--Utilities/cmcurl/lib/sendf.h6
-rw-r--r--Utilities/cmcurl/lib/setup-os400.h18
-rw-r--r--Utilities/cmcurl/lib/setup-vms.h47
-rw-r--r--Utilities/cmcurl/lib/share.c27
-rw-r--r--Utilities/cmcurl/lib/share.h4
-rw-r--r--Utilities/cmcurl/lib/slist.c4
-rw-r--r--Utilities/cmcurl/lib/smb.c976
-rw-r--r--Utilities/cmcurl/lib/smb.h271
-rw-r--r--Utilities/cmcurl/lib/smtp.c1019
-rw-r--r--Utilities/cmcurl/lib/smtp.h23
-rw-r--r--Utilities/cmcurl/lib/socks.c42
-rw-r--r--Utilities/cmcurl/lib/socks_gssapi.c80
-rw-r--r--Utilities/cmcurl/lib/socks_sspi.c59
-rw-r--r--Utilities/cmcurl/lib/splay.c10
-rw-r--r--Utilities/cmcurl/lib/ssh.c160
-rw-r--r--Utilities/cmcurl/lib/ssh.h36
-rw-r--r--Utilities/cmcurl/lib/strdup.c33
-rw-r--r--Utilities/cmcurl/lib/strdup.h3
-rw-r--r--Utilities/cmcurl/lib/strerror.c38
-rw-r--r--Utilities/cmcurl/lib/strtoofft.h11
-rw-r--r--Utilities/cmcurl/lib/telnet.c165
-rw-r--r--Utilities/cmcurl/lib/tftp.c163
-rw-r--r--Utilities/cmcurl/lib/timeval.c12
-rw-r--r--Utilities/cmcurl/lib/transfer.c145
-rw-r--r--Utilities/cmcurl/lib/transfer.h5
-rw-r--r--Utilities/cmcurl/lib/url.c744
-rw-r--r--Utilities/cmcurl/lib/url.h6
-rw-r--r--Utilities/cmcurl/lib/urldata.h162
-rw-r--r--Utilities/cmcurl/lib/version.c23
-rw-r--r--Utilities/cmcurl/lib/vtls/axtls.c34
-rw-r--r--Utilities/cmcurl/lib/vtls/axtls.h23
-rw-r--r--Utilities/cmcurl/lib/vtls/cyassl.c273
-rw-r--r--Utilities/cmcurl/lib/vtls/cyassl.h30
-rw-r--r--Utilities/cmcurl/lib/vtls/darwinssl.c (renamed from Utilities/cmcurl/lib/vtls/curl_darwinssl.c)137
-rw-r--r--Utilities/cmcurl/lib/vtls/darwinssl.h (renamed from Utilities/cmcurl/lib/vtls/curl_darwinssl.h)21
-rw-r--r--Utilities/cmcurl/lib/vtls/gskit.c326
-rw-r--r--Utilities/cmcurl/lib/vtls/gskit.h26
-rw-r--r--Utilities/cmcurl/lib/vtls/gtls.c398
-rw-r--r--Utilities/cmcurl/lib/vtls/gtls.h37
-rw-r--r--Utilities/cmcurl/lib/vtls/nss.c599
-rw-r--r--Utilities/cmcurl/lib/vtls/nssg.h41
-rw-r--r--Utilities/cmcurl/lib/vtls/openssl.c1091
-rw-r--r--Utilities/cmcurl/lib/vtls/openssl.h35
-rw-r--r--Utilities/cmcurl/lib/vtls/polarssl.c197
-rw-r--r--Utilities/cmcurl/lib/vtls/polarssl.h26
-rw-r--r--Utilities/cmcurl/lib/vtls/polarssl_threadlock.c5
-rw-r--r--Utilities/cmcurl/lib/vtls/qssl.c527
-rw-r--r--Utilities/cmcurl/lib/vtls/qssl.h62
-rw-r--r--Utilities/cmcurl/lib/vtls/schannel.c (renamed from Utilities/cmcurl/lib/vtls/curl_schannel.c)755
-rw-r--r--Utilities/cmcurl/lib/vtls/schannel.h (renamed from Utilities/cmcurl/lib/vtls/curl_schannel.h)39
-rw-r--r--Utilities/cmcurl/lib/vtls/vtls.c355
-rw-r--r--Utilities/cmcurl/lib/vtls/vtls.h55
-rw-r--r--Utilities/cmcurl/lib/wildcard.c20
-rw-r--r--Utilities/cmcurl/lib/x509asn1.c55
-rw-r--r--Utilities/cmcurl/lib/x509asn1.h11
-rwxr-xr-xbootstrap5
604 files changed, 21561 insertions, 15451 deletions
diff --git a/Auxiliary/cmake-mode.el b/Auxiliary/cmake-mode.el
index 02f0385..11e33b3 100644
--- a/Auxiliary/cmake-mode.el
+++ b/Auxiliary/cmake-mode.el
@@ -198,9 +198,9 @@ the indentation. Otherwise it retains the same position on the line"
,@(mapcar #'downcase cmake-keywords))
symbol-end))
. font-lock-keyword-face)
- (,(rx symbol-start (group (+ (or word (syntax symbol)))) ?\()
+ (,(rx symbol-start (group (+ (or word (syntax symbol)))) (* blank) ?\()
1 font-lock-function-name-face)
- ("\\${?\\([[:alpha:]_][[:alnum:]_]*\\|[0-9]+\\|[$*_]\\)"
+ (,(rx "${" (group (+(any alnum "-_+/."))) "}")
1 font-lock-variable-name-face t)
)
"Highlighting expressions for CMake mode.")
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a47c2ad..36244dd 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -72,7 +72,7 @@ endmacro()
# option to disable installing 3rd-party dependencies
option(CMake_INSTALL_DEPENDENCIES
- "Whether to install 3rd-party runtime dependencies" ON)
+ "Whether to install 3rd-party runtime dependencies" OFF)
mark_as_advanced(CMake_INSTALL_DEPENDENCIES)
#-----------------------------------------------------------------------
diff --git a/CTestCustom.cmake.in b/CTestCustom.cmake.in
index 7f20d10..f29ac70 100644
--- a/CTestCustom.cmake.in
+++ b/CTestCustom.cmake.in
@@ -109,3 +109,7 @@ set(CTEST_CUSTOM_COVERAGE_EXCLUDE
# Exclude Qt source files from coverage results:
"[A-Za-z]./[Qq]t/qt-.+-opensource-src"
)
+
+list(APPEND CTEST_CUSTOM_MEMCHECK_IGNORE
+ kwsys.testProcess-10 # See Source/kwsys/CTestCustom.cmake.in
+ )
diff --git a/Help/command/if.rst b/Help/command/if.rst
index 396becf..2465bde 100644
--- a/Help/command/if.rst
+++ b/Help/command/if.rst
@@ -71,6 +71,10 @@ Possible expressions are:
created by the :command:`add_executable`, :command:`add_library`, or
:command:`add_custom_target` commands.
+``if(TEST test-name)``
+ True if the given name is an existing test name created by the
+ :command:`add_test` command.
+
``if(EXISTS path-to-file-or-directory)``
True if the named file or directory exists. Behavior is well-defined
only for full paths.
diff --git a/Help/command/string.rst b/Help/command/string.rst
index bc4399c..20f8094 100644
--- a/Help/command/string.rst
+++ b/Help/command/string.rst
@@ -96,7 +96,7 @@ random number generator.
``FIND`` will return the position where the given substring was found in
the supplied string. If the ``REVERSE`` flag was used, the command will
search for the position of the last occurrence of the specified
-substring.
+substring. If the substring is not found, a position of -1 is returned.
The following characters have special meaning in regular expressions:
diff --git a/Help/command/try_compile.rst b/Help/command/try_compile.rst
index 9a70885..1ed24df 100644
--- a/Help/command/try_compile.rst
+++ b/Help/command/try_compile.rst
@@ -96,5 +96,16 @@ the try_compile call of interest, and then re-run cmake again with
Other Behavior Settings
^^^^^^^^^^^^^^^^^^^^^^^
+If set, the following variables are passed in to the generated
+try_compile CMakeLists.txt to initialize compile target properties with
+default values:
+
+* :variable:`CMAKE_LINK_SEARCH_START_STATIC`
+* :variable:`CMAKE_LINK_SEARCH_END_STATIC`
+* :variable:`CMAKE_POSITION_INDEPENDENT_CODE`
+
+If :policy:`CMP0056` is set to ``NEW``, then
+:variable:`CMAKE_EXE_LINKER_FLAGS` is passed in as well.
+
Set the :variable:`CMAKE_TRY_COMPILE_CONFIGURATION` variable to choose
a build configuration.
diff --git a/Help/manual/cmake-policies.7.rst b/Help/manual/cmake-policies.7.rst
index 0a313cd..590f10d 100644
--- a/Help/manual/cmake-policies.7.rst
+++ b/Help/manual/cmake-policies.7.rst
@@ -121,3 +121,4 @@ All Policies
/policy/CMP0061
/policy/CMP0062
/policy/CMP0063
+ /policy/CMP0064
diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst
index 9066d97..e0dbdeb 100644
--- a/Help/manual/cmake-variables.7.rst
+++ b/Help/manual/cmake-variables.7.rst
@@ -47,6 +47,8 @@ Variables that Provide Information
/variable/CMAKE_JOB_POOL_COMPILE
/variable/CMAKE_JOB_POOL_LINK
/variable/CMAKE_LINK_LIBRARY_SUFFIX
+ /variable/CMAKE_LINK_SEARCH_END_STATIC
+ /variable/CMAKE_LINK_SEARCH_START_STATIC
/variable/CMAKE_MAJOR_VERSION
/variable/CMAKE_MAKE_PROGRAM
/variable/CMAKE_MATCH_COUNT
diff --git a/Help/manual/cmake.1.rst b/Help/manual/cmake.1.rst
index 9ce4971..dac16bf 100644
--- a/Help/manual/cmake.1.rst
+++ b/Help/manual/cmake.1.rst
@@ -27,6 +27,8 @@ in each directory of a source tree with the name CMakeLists.txt.
Users build a project by using CMake to generate a build system for a
native tool on their platform.
+.. _`CMake Options`:
+
Options
=======
diff --git a/Help/policy/CMP0064.rst b/Help/policy/CMP0064.rst
new file mode 100644
index 0000000..e9a061b
--- /dev/null
+++ b/Help/policy/CMP0064.rst
@@ -0,0 +1,17 @@
+CMP0064
+-------
+
+Recognize ``TEST`` as a operator for the :command:`if` command.
+
+The ``TEST`` operator was added to the :command:`if` command to determine if a
+given test name was created by the :command:`add_test` command.
+
+The ``OLD`` behavior for this policy is to ignore the ``TEST`` operator.
+The ``NEW`` behavior is to interpret the ``TEST`` operator.
+
+This policy was introduced in CMake version 3.4. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior. Use
+the :command:`cmake_policy()` command to set it to ``OLD`` or ``NEW``
+explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/prop_gbl/RULE_LAUNCH_COMPILE.rst b/Help/prop_gbl/RULE_LAUNCH_COMPILE.rst
index 980843b..e0df878 100644
--- a/Help/prop_gbl/RULE_LAUNCH_COMPILE.rst
+++ b/Help/prop_gbl/RULE_LAUNCH_COMPILE.rst
@@ -3,7 +3,9 @@ RULE_LAUNCH_COMPILE
Specify a launcher for compile rules.
-Makefile generators prefix compiler commands with the given launcher
-command line. This is intended to allow launchers to intercept build
-problems with high granularity. Non-Makefile generators currently
-ignore this property.
+:ref:`Makefile Generators` and the :generator:`Ninja` generator prefix
+compiler commands with the given launcher command line.
+This is intended to allow launchers to intercept build problems
+with high granularity. Other generators ignore this property
+because their underlying build systems provide no hook to wrap
+individual commands with a launcher.
diff --git a/Help/prop_gbl/RULE_LAUNCH_CUSTOM.rst b/Help/prop_gbl/RULE_LAUNCH_CUSTOM.rst
index 9d4a25c..b20c59b 100644
--- a/Help/prop_gbl/RULE_LAUNCH_CUSTOM.rst
+++ b/Help/prop_gbl/RULE_LAUNCH_CUSTOM.rst
@@ -3,7 +3,9 @@ RULE_LAUNCH_CUSTOM
Specify a launcher for custom rules.
-Makefile generators prefix custom commands with the given launcher
-command line. This is intended to allow launchers to intercept build
-problems with high granularity. Non-Makefile generators currently
-ignore this property.
+:ref:`Makefile Generators` and the :generator:`Ninja` generator prefix
+custom commands with the given launcher command line.
+This is intended to allow launchers to intercept build problems
+with high granularity. Other generators ignore this property
+because their underlying build systems provide no hook to wrap
+individual commands with a launcher.
diff --git a/Help/prop_gbl/RULE_LAUNCH_LINK.rst b/Help/prop_gbl/RULE_LAUNCH_LINK.rst
index 191f1d5..567bb68 100644
--- a/Help/prop_gbl/RULE_LAUNCH_LINK.rst
+++ b/Help/prop_gbl/RULE_LAUNCH_LINK.rst
@@ -3,7 +3,9 @@ RULE_LAUNCH_LINK
Specify a launcher for link rules.
-Makefile generators prefix link and archive commands with the given
-launcher command line. This is intended to allow launchers to
-intercept build problems with high granularity. Non-Makefile
-generators currently ignore this property.
+:ref:`Makefile Generators` and the :generator:`Ninja` generator prefix
+link and archive commands with the given launcher command line.
+This is intended to allow launchers to intercept build problems
+with high granularity. Other generators ignore this property
+because their underlying build systems provide no hook to wrap
+individual commands with a launcher.
diff --git a/Help/prop_tgt/ARCHIVE_OUTPUT_DIRECTORY_CONFIG.rst b/Help/prop_tgt/ARCHIVE_OUTPUT_DIRECTORY_CONFIG.rst
index 29991eb..12f8bb7 100644
--- a/Help/prop_tgt/ARCHIVE_OUTPUT_DIRECTORY_CONFIG.rst
+++ b/Help/prop_tgt/ARCHIVE_OUTPUT_DIRECTORY_CONFIG.rst
@@ -11,3 +11,6 @@ per-configuration subdirectory to the specified directory. This
property is initialized by the value of the
:variable:`CMAKE_ARCHIVE_OUTPUT_DIRECTORY_<CONFIG>` variable if
it is set when a target is created.
+
+Contents of ``ARCHIVE_OUTPUT_DIRECTORY_<CONFIG>`` may use
+:manual:`generator expressions <cmake-generator-expressions(7)>`.
diff --git a/Help/prop_tgt/LIBRARY_OUTPUT_DIRECTORY_CONFIG.rst b/Help/prop_tgt/LIBRARY_OUTPUT_DIRECTORY_CONFIG.rst
index 6fc0142..28dd404 100644
--- a/Help/prop_tgt/LIBRARY_OUTPUT_DIRECTORY_CONFIG.rst
+++ b/Help/prop_tgt/LIBRARY_OUTPUT_DIRECTORY_CONFIG.rst
@@ -11,3 +11,6 @@ per-configuration subdirectory to the specified directory. This
property is initialized by the value of the
:variable:`CMAKE_LIBRARY_OUTPUT_DIRECTORY_<CONFIG>` variable if
it is set when a target is created.
+
+Contents of ``LIBRARY_OUTPUT_DIRECTORY_<CONFIG>`` may use
+:manual:`generator expressions <cmake-generator-expressions(7)>`.
diff --git a/Help/prop_tgt/LINK_SEARCH_END_STATIC.rst b/Help/prop_tgt/LINK_SEARCH_END_STATIC.rst
index fe105bd..cf9c871 100644
--- a/Help/prop_tgt/LINK_SEARCH_END_STATIC.rst
+++ b/Help/prop_tgt/LINK_SEARCH_END_STATIC.rst
@@ -10,5 +10,9 @@ paths are not known or (in some cases) are in implicit link
directories for the platform. By default CMake adds an option at the
end of the library list (if necessary) to set the linker search type
back to its starting type. This property switches the final linker
-search type to -Bstatic regardless of how it started. See also
-LINK_SEARCH_START_STATIC.
+search type to -Bstatic regardless of how it started.
+
+This property is initialized by the value of the variable
+CMAKE_LINK_SEARCH_END_STATIC if it is set when a target is created.
+
+See also LINK_SEARCH_START_STATIC.
diff --git a/Help/prop_tgt/LINK_SEARCH_START_STATIC.rst b/Help/prop_tgt/LINK_SEARCH_START_STATIC.rst
index ca899fe..2e0f9bd 100644
--- a/Help/prop_tgt/LINK_SEARCH_START_STATIC.rst
+++ b/Help/prop_tgt/LINK_SEARCH_START_STATIC.rst
@@ -11,4 +11,9 @@ directories for the platform. By default the linker search type is
assumed to be -Bdynamic at the beginning of the library list. This
property switches the assumption to -Bstatic. It is intended for use
when linking an executable statically (e.g. with the GNU -static
-option). See also LINK_SEARCH_END_STATIC.
+option).
+
+This property is initialized by the value of the variable
+CMAKE_LINK_SEARCH_START_STATIC if it is set when a target is created.
+
+See also LINK_SEARCH_END_STATIC.
diff --git a/Help/prop_tgt/RUNTIME_OUTPUT_DIRECTORY_CONFIG.rst b/Help/prop_tgt/RUNTIME_OUTPUT_DIRECTORY_CONFIG.rst
index c100346..94fb277 100644
--- a/Help/prop_tgt/RUNTIME_OUTPUT_DIRECTORY_CONFIG.rst
+++ b/Help/prop_tgt/RUNTIME_OUTPUT_DIRECTORY_CONFIG.rst
@@ -11,3 +11,6 @@ per-configuration subdirectory to the specified directory. This
property is initialized by the value of the
:variable:`CMAKE_RUNTIME_OUTPUT_DIRECTORY_<CONFIG>` variable if
it is set when a target is created.
+
+Contents of ``RUNTIME_OUTPUT_DIRECTORY_<CONFIG>`` may use
+:manual:`generator expressions <cmake-generator-expressions(7)>`.
diff --git a/Help/prop_tgt/XXX_OUTPUT_DIRECTORY.txt b/Help/prop_tgt/XXX_OUTPUT_DIRECTORY.txt
index 0b3d31c..3ae5448 100644
--- a/Help/prop_tgt/XXX_OUTPUT_DIRECTORY.txt
+++ b/Help/prop_tgt/XXX_OUTPUT_DIRECTORY.txt
@@ -1,8 +1,11 @@
Output directory in which to build |XXX| target files.
This property specifies the directory into which |xxx| target files
-should be built. Multi-configuration generators (VS, Xcode) append a
-per-configuration subdirectory to the specified directory.
+should be built. The property value may use
+:manual:`generator expressions <cmake-generator-expressions(7)>`.
+Multi-configuration generators (VS, Xcode) append a per-configuration
+subdirectory to the specified directory unless a generator expression
+is used.
This property is initialized by the value of the variable
|CMAKE_XXX_OUTPUT_DIRECTORY| if it is set when a target is created.
diff --git a/Help/release/dev/FindTIFF-updates.rst b/Help/release/dev/FindTIFF-updates.rst
new file mode 100644
index 0000000..083e40f
--- /dev/null
+++ b/Help/release/dev/FindTIFF-updates.rst
@@ -0,0 +1,5 @@
+FindTIFF-updates
+----------------
+
+* The :module:`FindTIFF` module learned to search separately for
+ debug and release variants.
diff --git a/Help/release/dev/FindXercesC-updates.rst b/Help/release/dev/FindXercesC-updates.rst
new file mode 100644
index 0000000..47a8ada
--- /dev/null
+++ b/Help/release/dev/FindXercesC-updates.rst
@@ -0,0 +1,5 @@
+FindXercesC-updates
+-------------------
+
+* The :module:`FindXercesC` module learned to search separately for
+ debug and release variants.
diff --git a/Help/release/dev/OUTPUT_DIRECTORY-genex.rst b/Help/release/dev/OUTPUT_DIRECTORY-genex.rst
new file mode 100644
index 0000000..8b839c0
--- /dev/null
+++ b/Help/release/dev/OUTPUT_DIRECTORY-genex.rst
@@ -0,0 +1,7 @@
+OUTPUT_DIRECTORY-genex
+----------------------
+
+* The :prop_tgt:`ARCHIVE_OUTPUT_DIRECTORY`,
+ :prop_tgt:`LIBRARY_OUTPUT_DIRECTORY`, and
+ :prop_tgt:`RUNTIME_OUTPUT_DIRECTORY` target properties learned to
+ support :manual:`generator expressions <cmake-generator-expressions(7)>`.
diff --git a/Help/release/dev/add-link-search-static-properties-defaults.rst b/Help/release/dev/add-link-search-static-properties-defaults.rst
new file mode 100644
index 0000000..98dda30
--- /dev/null
+++ b/Help/release/dev/add-link-search-static-properties-defaults.rst
@@ -0,0 +1,9 @@
+add-link-search-static-properties-defaults
+------------------------------------------
+
+* New :variable:`CMAKE_LINK_SEARCH_START_STATIC` and
+ :variable:`CMAKE_LINK_SEARCH_END_STATIC` variables were
+ introduced to initialize the
+ :prop_tgt:`LINK_SEARCH_START_STATIC` and
+ :prop_tgt:`LINK_SEARCH_END_STATIC` target properties,
+ respectively.
diff --git a/Help/release/dev/if-TEST.rst b/Help/release/dev/if-TEST.rst
new file mode 100644
index 0000000..05bf71c
--- /dev/null
+++ b/Help/release/dev/if-TEST.rst
@@ -0,0 +1,5 @@
+if-TEST
+-------
+
+* Add a new TEST operator to if() that evaluates to true
+ if a given test name has been defined.
diff --git a/Help/release/dev/java-updates.rst b/Help/release/dev/java-updates.rst
new file mode 100644
index 0000000..b777807
--- /dev/null
+++ b/Help/release/dev/java-updates.rst
@@ -0,0 +1,13 @@
+java-updates
+------------
+
+* The :module:`FindJava` module learned to optionally find
+ the ``idlj`` and ``jarsigner`` tools.
+
+* The :module:`UseJava` module ``add_jar`` function learned
+ to support response files (e.g. ``@srcs.txt``) for source
+ specification.
+
+* The :module:`UseJava` module ``install_jar`` function learned
+ new ``DESTINATION`` and ``COMPONENT`` options to specify
+ the corresponding :command:`install` command options.
diff --git a/Help/variable/APPLE.rst b/Help/variable/APPLE.rst
index 3afdee8..a8d2429 100644
--- a/Help/variable/APPLE.rst
+++ b/Help/variable/APPLE.rst
@@ -1,6 +1,6 @@
APPLE
-----
-True if running on Mac OS X.
+``True`` if running on Mac OS X.
-Set to true on Mac OS X.
+Set to ``true`` on Mac OS X.
diff --git a/Help/variable/BORLAND.rst b/Help/variable/BORLAND.rst
index 4af6085..badb733 100644
--- a/Help/variable/BORLAND.rst
+++ b/Help/variable/BORLAND.rst
@@ -1,6 +1,6 @@
BORLAND
-------
-True if the Borland compiler is being used.
+``True`` if the Borland compiler is being used.
-This is set to true if the Borland compiler is being used.
+This is set to ``true`` if the Borland compiler is being used.
diff --git a/Help/variable/BUILD_SHARED_LIBS.rst b/Help/variable/BUILD_SHARED_LIBS.rst
index 6f30efb..53087b2 100644
--- a/Help/variable/BUILD_SHARED_LIBS.rst
+++ b/Help/variable/BUILD_SHARED_LIBS.rst
@@ -1,10 +1,10 @@
BUILD_SHARED_LIBS
-----------------
-Global flag to cause add_library to create shared libraries if on.
+Global flag to cause :command:`add_library` to create shared libraries if on.
If present and true, this will cause all libraries to be built shared
unless the library was explicitly added as a static library. This
-variable is often added to projects as an OPTION so that each user of
-a project can decide if they want to build the project using shared or
+variable is often added to projects as an :command:`option` so that each user
+of a project can decide if they want to build the project using shared or
static libraries.
diff --git a/Help/variable/CMAKE_ABSOLUTE_DESTINATION_FILES.rst b/Help/variable/CMAKE_ABSOLUTE_DESTINATION_FILES.rst
index 3691453..b6d0054 100644
--- a/Help/variable/CMAKE_ABSOLUTE_DESTINATION_FILES.rst
+++ b/Help/variable/CMAKE_ABSOLUTE_DESTINATION_FILES.rst
@@ -1,9 +1,9 @@
CMAKE_ABSOLUTE_DESTINATION_FILES
--------------------------------
-List of files which have been installed using an ABSOLUTE DESTINATION path.
+List of files which have been installed using an ``ABSOLUTE DESTINATION`` path.
-This variable is defined by CMake-generated cmake_install.cmake
+This variable is defined by CMake-generated ``cmake_install.cmake``
scripts. It can be used (read-only) by programs or scripts that
source those install scripts. This is used by some CPack generators
(e.g. RPM).
diff --git a/Help/variable/CMAKE_ANDROID_NATIVE_LIB_DEPENDENCIES.rst b/Help/variable/CMAKE_ANDROID_NATIVE_LIB_DEPENDENCIES.rst
index 52e60b1..4191907 100644
--- a/Help/variable/CMAKE_ANDROID_NATIVE_LIB_DEPENDENCIES.rst
+++ b/Help/variable/CMAKE_ANDROID_NATIVE_LIB_DEPENDENCIES.rst
@@ -1,5 +1,5 @@
CMAKE_ANDROID_NATIVE_LIB_DEPENDENCIES
-------------------------------------
-Default value for the :prop_tgt:`ANDROID_NATIVE_LIB_DEPENDENCIES` target property.
-See that target property for additional information.
+Default value for the :prop_tgt:`ANDROID_NATIVE_LIB_DEPENDENCIES` target
+property. See that target property for additional information.
diff --git a/Help/variable/CMAKE_ANDROID_NATIVE_LIB_DIRECTORIES.rst b/Help/variable/CMAKE_ANDROID_NATIVE_LIB_DIRECTORIES.rst
index 8480575..7cb9527 100644
--- a/Help/variable/CMAKE_ANDROID_NATIVE_LIB_DIRECTORIES.rst
+++ b/Help/variable/CMAKE_ANDROID_NATIVE_LIB_DIRECTORIES.rst
@@ -1,5 +1,5 @@
CMAKE_ANDROID_NATIVE_LIB_DIRECTORIES
------------------------------------
-Default value for the :prop_tgt:`ANDROID_NATIVE_LIB_DIRECTORIES` target property.
-See that target property for additional information.
+Default value for the :prop_tgt:`ANDROID_NATIVE_LIB_DIRECTORIES` target
+property. See that target property for additional information.
diff --git a/Help/variable/CMAKE_ARGC.rst b/Help/variable/CMAKE_ARGC.rst
index be120b8..aec9711 100644
--- a/Help/variable/CMAKE_ARGC.rst
+++ b/Help/variable/CMAKE_ARGC.rst
@@ -3,5 +3,6 @@ CMAKE_ARGC
Number of command line arguments passed to CMake in script mode.
-When run in -P script mode, CMake sets this variable to the number of
-command line arguments. See also CMAKE_ARGV0, 1, 2 ...
+When run in :ref:`-P <CMake Options>` script mode, CMake sets this variable to
+the number of command line arguments. See also :variable:`CMAKE_ARGV0`,
+``1``, ``2`` ...
diff --git a/Help/variable/CMAKE_ARGV0.rst b/Help/variable/CMAKE_ARGV0.rst
index e5ed419..8b1ecb7 100644
--- a/Help/variable/CMAKE_ARGV0.rst
+++ b/Help/variable/CMAKE_ARGV0.rst
@@ -3,7 +3,7 @@ CMAKE_ARGV0
Command line argument passed to CMake in script mode.
-When run in -P script mode, CMake sets this variable to the first
-command line argument. It then also sets CMAKE_ARGV1, CMAKE_ARGV2,
-... and so on, up to the number of command line arguments given. See
-also CMAKE_ARGC.
+When run in :ref:`-P <CMake Options>` script mode, CMake sets this variable to
+the first command line argument. It then also sets ``CMAKE_ARGV1``,
+``CMAKE_ARGV2``, ... and so on, up to the number of command line arguments
+given. See also :variable:`CMAKE_ARGC`.
diff --git a/Help/variable/CMAKE_AUTOMOC_RELAXED_MODE.rst b/Help/variable/CMAKE_AUTOMOC_RELAXED_MODE.rst
index a814d40..addc62d 100644
--- a/Help/variable/CMAKE_AUTOMOC_RELAXED_MODE.rst
+++ b/Help/variable/CMAKE_AUTOMOC_RELAXED_MODE.rst
@@ -3,11 +3,11 @@ CMAKE_AUTOMOC_RELAXED_MODE
Switch between strict and relaxed automoc mode.
-By default, :prop_tgt:`AUTOMOC` behaves exactly as described in the documentation
-of the :prop_tgt:`AUTOMOC` target property. When set to ``TRUE``, it accepts more
-input and tries to find the correct input file for ``moc`` even if it
-differs from the documented behaviour. In this mode it e.g. also
-checks whether a header file is intended to be processed by moc when a
-``"foo.moc"`` file has been included.
+By default, :prop_tgt:`AUTOMOC` behaves exactly as described in the
+documentation of the :prop_tgt:`AUTOMOC` target property. When set to
+``TRUE``, it accepts more input and tries to find the correct input file for
+``moc`` even if it differs from the documented behaviour. In this mode it
+e.g. also checks whether a header file is intended to be processed by moc
+when a ``"foo.moc"`` file has been included.
Relaxed mode has to be enabled for KDE4 compatibility.
diff --git a/Help/variable/CMAKE_AUTORCC.rst b/Help/variable/CMAKE_AUTORCC.rst
index 067f766..7426105 100644
--- a/Help/variable/CMAKE_AUTORCC.rst
+++ b/Help/variable/CMAKE_AUTORCC.rst
@@ -3,5 +3,5 @@ CMAKE_AUTORCC
Whether to handle ``rcc`` automatically for Qt targets.
-This variable is used to initialize the :prop_tgt:`AUTORCC` property on all the targets.
-See that target property for additional information.
+This variable is used to initialize the :prop_tgt:`AUTORCC` property on all
+the targets. See that target property for additional information.
diff --git a/Help/variable/CMAKE_AUTOUIC.rst b/Help/variable/CMAKE_AUTOUIC.rst
index 0beb555..5abefaa 100644
--- a/Help/variable/CMAKE_AUTOUIC.rst
+++ b/Help/variable/CMAKE_AUTOUIC.rst
@@ -3,5 +3,5 @@ CMAKE_AUTOUIC
Whether to handle ``uic`` automatically for Qt targets.
-This variable is used to initialize the :prop_tgt:`AUTOUIC` property on all the targets.
-See that target property for additional information.
+This variable is used to initialize the :prop_tgt:`AUTOUIC` property on all
+the targets. See that target property for additional information.
diff --git a/Help/variable/CMAKE_BINARY_DIR.rst b/Help/variable/CMAKE_BINARY_DIR.rst
index 703bb58..f8dd8ab 100644
--- a/Help/variable/CMAKE_BINARY_DIR.rst
+++ b/Help/variable/CMAKE_BINARY_DIR.rst
@@ -5,4 +5,4 @@ The path to the top level of the build tree.
This is the full path to the top level of the current CMake build
tree. For an in-source build, this would be the same as
-CMAKE_SOURCE_DIR.
+:variable:`CMAKE_SOURCE_DIR`.
diff --git a/Help/variable/CMAKE_BUILD_TYPE.rst b/Help/variable/CMAKE_BUILD_TYPE.rst
index 68f08ba..2d54d60 100644
--- a/Help/variable/CMAKE_BUILD_TYPE.rst
+++ b/Help/variable/CMAKE_BUILD_TYPE.rst
@@ -4,16 +4,17 @@ CMAKE_BUILD_TYPE
Specifies the build type on single-configuration generators.
This statically specifies what build type (configuration) will be
-built in this build tree. Possible values are empty, Debug, Release,
-RelWithDebInfo and MinSizeRel. This variable is only meaningful to
-single-configuration generators (such as make and Ninja) i.e. those
-which choose a single configuration when CMake runs to generate a
-build tree as opposed to multi-configuration generators which offer
-selection of the build configuration within the generated build
+built in this build tree. Possible values are empty, ``Debug``, ``Release``,
+``RelWithDebInfo`` and ``MinSizeRel``. This variable is only meaningful to
+single-configuration generators (such as :ref:`Makefile Generators` and
+:generator:`Ninja`) i.e. those which choose a single configuration when CMake
+runs to generate a build tree as opposed to multi-configuration generators
+which offer selection of the build configuration within the generated build
environment. There are many per-config properties and variables
-(usually following clean SOME_VAR_<CONFIG> order conventions), such as
-CMAKE_C_FLAGS_<CONFIG>, specified as uppercase:
-CMAKE_C_FLAGS_[DEBUG|RELEASE|RELWITHDEBINFO|MINSIZEREL]. For example,
-in a build tree configured to build type Debug, CMake will see to
-having CMAKE_C_FLAGS_DEBUG settings get added to the CMAKE_C_FLAGS
-settings. See also CMAKE_CONFIGURATION_TYPES.
+(usually following clean ``SOME_VAR_<CONFIG>`` order conventions), such as
+``CMAKE_C_FLAGS_<CONFIG>``, specified as uppercase:
+``CMAKE_C_FLAGS_[DEBUG|RELEASE|RELWITHDEBINFO|MINSIZEREL]``. For example,
+in a build tree configured to build type ``Debug``, CMake will see to
+having :variable:`CMAKE_C_FLAGS_DEBUG <CMAKE_<LANG>_FLAGS_DEBUG>` settings get
+added to the :variable:`CMAKE_C_FLAGS <CMAKE_<LANG>_FLAGS>` settings. See
+also :variable:`CMAKE_CONFIGURATION_TYPES`.
diff --git a/Help/variable/CMAKE_BUILD_WITH_INSTALL_RPATH.rst b/Help/variable/CMAKE_BUILD_WITH_INSTALL_RPATH.rst
index 6875da6..5b59a6e 100644
--- a/Help/variable/CMAKE_BUILD_WITH_INSTALL_RPATH.rst
+++ b/Help/variable/CMAKE_BUILD_WITH_INSTALL_RPATH.rst
@@ -1,11 +1,11 @@
CMAKE_BUILD_WITH_INSTALL_RPATH
------------------------------
-Use the install path for the RPATH
+Use the install path for the ``RPATH``.
-Normally CMake uses the build tree for the RPATH when building
-executables etc on systems that use RPATH. When the software is
+Normally CMake uses the build tree for the ``RPATH`` when building
+executables etc on systems that use ``RPATH``. When the software is
installed the executables etc are relinked by CMake to have the
-install RPATH. If this variable is set to true then the software is
-always built with the install path for the RPATH and does not need to
+install ``RPATH``. If this variable is set to true then the software is
+always built with the install path for the ``RPATH`` and does not need to
be relinked when installed.
diff --git a/Help/variable/CMAKE_CACHEFILE_DIR.rst b/Help/variable/CMAKE_CACHEFILE_DIR.rst
index 78c7d93..8604d0e 100644
--- a/Help/variable/CMAKE_CACHEFILE_DIR.rst
+++ b/Help/variable/CMAKE_CACHEFILE_DIR.rst
@@ -1,7 +1,7 @@
CMAKE_CACHEFILE_DIR
-------------------
-The directory with the CMakeCache.txt file.
+The directory with the ``CMakeCache.txt`` file.
-This is the full path to the directory that has the CMakeCache.txt
-file in it. This is the same as CMAKE_BINARY_DIR.
+This is the full path to the directory that has the ``CMakeCache.txt``
+file in it. This is the same as :variable:`CMAKE_BINARY_DIR`.
diff --git a/Help/variable/CMAKE_CACHE_MAJOR_VERSION.rst b/Help/variable/CMAKE_CACHE_MAJOR_VERSION.rst
index e6887d9..1e53ed6 100644
--- a/Help/variable/CMAKE_CACHE_MAJOR_VERSION.rst
+++ b/Help/variable/CMAKE_CACHE_MAJOR_VERSION.rst
@@ -1,7 +1,7 @@
CMAKE_CACHE_MAJOR_VERSION
-------------------------
-Major version of CMake used to create the CMakeCache.txt file
+Major version of CMake used to create the ``CMakeCache.txt`` file
This stores the major version of CMake used to write a CMake cache
file. It is only different when a different version of CMake is run
diff --git a/Help/variable/CMAKE_CACHE_MINOR_VERSION.rst b/Help/variable/CMAKE_CACHE_MINOR_VERSION.rst
index 799f0a9..5d174a3 100644
--- a/Help/variable/CMAKE_CACHE_MINOR_VERSION.rst
+++ b/Help/variable/CMAKE_CACHE_MINOR_VERSION.rst
@@ -1,7 +1,7 @@
CMAKE_CACHE_MINOR_VERSION
-------------------------
-Minor version of CMake used to create the CMakeCache.txt file
+Minor version of CMake used to create the ``CMakeCache.txt`` file
This stores the minor version of CMake used to write a CMake cache
file. It is only different when a different version of CMake is run
diff --git a/Help/variable/CMAKE_CACHE_PATCH_VERSION.rst b/Help/variable/CMAKE_CACHE_PATCH_VERSION.rst
index e67d544..22d267c 100644
--- a/Help/variable/CMAKE_CACHE_PATCH_VERSION.rst
+++ b/Help/variable/CMAKE_CACHE_PATCH_VERSION.rst
@@ -1,7 +1,7 @@
CMAKE_CACHE_PATCH_VERSION
-------------------------
-Patch version of CMake used to create the CMakeCache.txt file
+Patch version of CMake used to create the ``CMakeCache.txt`` file
This stores the patch version of CMake used to write a CMake cache
file. It is only different when a different version of CMake is run
diff --git a/Help/variable/CMAKE_CFG_INTDIR.rst b/Help/variable/CMAKE_CFG_INTDIR.rst
index 55f7b01..dcc1aed 100644
--- a/Help/variable/CMAKE_CFG_INTDIR.rst
+++ b/Help/variable/CMAKE_CFG_INTDIR.rst
@@ -4,11 +4,11 @@ CMAKE_CFG_INTDIR
Build-time reference to per-configuration output subdirectory.
For native build systems supporting multiple configurations in the
-build tree (such as Visual Studio and Xcode), the value is a reference
-to a build-time variable specifying the name of the per-configuration
-output subdirectory. On Makefile generators this evaluates to "."
-because there is only one configuration in a build tree. Example
-values:
+build tree (such as :ref:`Visual Studio Generators` and :generator:`Xcode`),
+the value is a reference to a build-time variable specifying the name
+of the per-configuration output subdirectory. On :ref:`Makefile Generators`
+this evaluates to `.` because there is only one configuration in a build tree.
+Example values:
::
@@ -33,13 +33,14 @@ evaluated at build time. Example of intended usage:
)
add_custom_target(drive ALL DEPENDS out.txt)
-Note that CMAKE_CFG_INTDIR is no longer necessary for this purpose but
+Note that ``CMAKE_CFG_INTDIR`` is no longer necessary for this purpose but
has been left for compatibility with existing projects. Instead
-add_custom_command() recognizes executable target names in its COMMAND
-option, so "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/mytool"
-can be replaced by just "mytool".
+:command:`add_custom_command` recognizes executable target names in its
+``COMMAND`` option, so
+``${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/mytool`` can be replaced
+by just ``mytool``.
This variable is read-only. Setting it is undefined behavior. In
multi-configuration build systems the value of this variable is passed
-as the value of preprocessor symbol "CMAKE_INTDIR" to the compilation
+as the value of preprocessor symbol ``CMAKE_INTDIR`` to the compilation
of all source files.
diff --git a/Help/variable/CMAKE_CL_64.rst b/Help/variable/CMAKE_CL_64.rst
index 5096829..a1e86a5 100644
--- a/Help/variable/CMAKE_CL_64.rst
+++ b/Help/variable/CMAKE_CL_64.rst
@@ -1,6 +1,6 @@
CMAKE_CL_64
-----------
-Using the 64 bit compiler from Microsoft
+Using the 64-bit compiler from Microsoft
-Set to true when using the 64 bit cl compiler from Microsoft.
+Set to ``true`` when using the 64-bit ``cl`` compiler from Microsoft.
diff --git a/Help/variable/CMAKE_COLOR_MAKEFILE.rst b/Help/variable/CMAKE_COLOR_MAKEFILE.rst
index 170baf3..bb86ecc 100644
--- a/Help/variable/CMAKE_COLOR_MAKEFILE.rst
+++ b/Help/variable/CMAKE_COLOR_MAKEFILE.rst
@@ -1,7 +1,7 @@
CMAKE_COLOR_MAKEFILE
--------------------
-Enables color output when using the Makefile generator.
+Enables color output when using the :ref:`Makefile Generators`.
When enabled, the generated Makefiles will produce colored output.
-Default is ON.
+Default is ``ON``.
diff --git a/Help/variable/CMAKE_COMMAND.rst b/Help/variable/CMAKE_COMMAND.rst
index f4e5f1e..f80b46c 100644
--- a/Help/variable/CMAKE_COMMAND.rst
+++ b/Help/variable/CMAKE_COMMAND.rst
@@ -1,8 +1,8 @@
CMAKE_COMMAND
-------------
-The full path to the cmake executable.
+The full path to the :manual:`cmake(1)` executable.
-This is the full path to the CMake executable cmake which is useful
-from custom commands that want to use the cmake -E option for portable
-system commands. (e.g. /usr/local/bin/cmake
+This is the full path to the CMake executable :manual:`cmake(1)` which is
+useful from custom commands that want to use the ``cmake -E`` option for
+portable system commands. (e.g. ``/usr/local/bin/cmake``)
diff --git a/Help/variable/CMAKE_COMPILER_IS_GNULANG.rst b/Help/variable/CMAKE_COMPILER_IS_GNULANG.rst
index bc5652f..4b652c0 100644
--- a/Help/variable/CMAKE_COMPILER_IS_GNULANG.rst
+++ b/Help/variable/CMAKE_COMPILER_IS_GNULANG.rst
@@ -3,10 +3,10 @@ CMAKE_COMPILER_IS_GNU<LANG>
True if the compiler is GNU.
-If the selected <LANG> compiler is the GNU compiler then this is TRUE,
-if not it is FALSE. Unlike the other per-language variables, this
+If the selected ``<LANG>`` compiler is the GNU compiler then this is ``TRUE``,
+if not it is ``FALSE``. Unlike the other per-language variables, this
uses the GNU syntax for identifying languages instead of the CMake
-syntax. Recognized values of the <LANG> suffix are:
+syntax. Recognized values of the ``<LANG>`` suffix are:
::
diff --git a/Help/variable/CMAKE_CONFIGURATION_TYPES.rst b/Help/variable/CMAKE_CONFIGURATION_TYPES.rst
index 986b969..34e99eb 100644
--- a/Help/variable/CMAKE_CONFIGURATION_TYPES.rst
+++ b/Help/variable/CMAKE_CONFIGURATION_TYPES.rst
@@ -4,7 +4,7 @@ CMAKE_CONFIGURATION_TYPES
Specifies the available build types on multi-config generators.
This specifies what build types (configurations) will be available
-such as Debug, Release, RelWithDebInfo etc. This has reasonable
+such as ``Debug``, ``Release``, ``RelWithDebInfo`` etc. This has reasonable
defaults on most platforms, but can be extended to provide other build
-types. See also CMAKE_BUILD_TYPE for details of managing
-configuration data, and CMAKE_CFG_INTDIR.
+types. See also :variable:`CMAKE_BUILD_TYPE` for details of managing
+configuration data, and :variable:`CMAKE_CFG_INTDIR`.
diff --git a/Help/variable/CMAKE_CONFIG_POSTFIX.rst b/Help/variable/CMAKE_CONFIG_POSTFIX.rst
index af38bed..e686a43 100644
--- a/Help/variable/CMAKE_CONFIG_POSTFIX.rst
+++ b/Help/variable/CMAKE_CONFIG_POSTFIX.rst
@@ -1,7 +1,7 @@
CMAKE_<CONFIG>_POSTFIX
----------------------
-Default filename postfix for libraries under configuration <CONFIG>.
+Default filename postfix for libraries under configuration ``<CONFIG>``.
-When a non-executable target is created its <CONFIG>_POSTFIX target
-property is initialized with the value of this variable if it is set.
+When a non-executable target is created its :prop_tgt:`<CONFIG>_POSTFIX`
+target property is initialized with the value of this variable if it is set.
diff --git a/Help/variable/CMAKE_CTEST_COMMAND.rst b/Help/variable/CMAKE_CTEST_COMMAND.rst
index d5dd2c3..b2942e2 100644
--- a/Help/variable/CMAKE_CTEST_COMMAND.rst
+++ b/Help/variable/CMAKE_CTEST_COMMAND.rst
@@ -1,8 +1,8 @@
CMAKE_CTEST_COMMAND
-------------------
-Full path to ctest command installed with cmake.
+Full path to :manual:`ctest(1)` command installed with CMake.
-This is the full path to the CTest executable ctest which is useful
-from custom commands that want to use the cmake -E option for portable
-system commands.
+This is the full path to the CTest executable :manual:`ctest(1)` which is
+useful from custom commands that want to use the :manual:`cmake(1)` ``-E``
+option for portable system commands.
diff --git a/Help/variable/CMAKE_CURRENT_BINARY_DIR.rst b/Help/variable/CMAKE_CURRENT_BINARY_DIR.rst
index fb55a11..cc3b639 100644
--- a/Help/variable/CMAKE_CURRENT_BINARY_DIR.rst
+++ b/Help/variable/CMAKE_CURRENT_BINARY_DIR.rst
@@ -4,7 +4,7 @@ CMAKE_CURRENT_BINARY_DIR
The path to the binary directory currently being processed.
This the full path to the build directory that is currently being
-processed by cmake. Each directory added by add_subdirectory will
+processed by cmake. Each directory added by :command:`add_subdirectory` will
create a binary directory in the build tree, and as it is being
processed this variable will be set. For in-source builds this is the
current source directory being processed.
diff --git a/Help/variable/CMAKE_CURRENT_LIST_DIR.rst b/Help/variable/CMAKE_CURRENT_LIST_DIR.rst
index b816821..ebc3ab9 100644
--- a/Help/variable/CMAKE_CURRENT_LIST_DIR.rst
+++ b/Help/variable/CMAKE_CURRENT_LIST_DIR.rst
@@ -5,8 +5,8 @@ Full directory of the listfile currently being processed.
As CMake processes the listfiles in your project this variable will
always be set to the directory where the listfile which is currently
-being processed (CMAKE_CURRENT_LIST_FILE) is located. The value has
-dynamic scope. When CMake starts processing commands in a source file
+being processed (:variable:`CMAKE_CURRENT_LIST_FILE`) is located. The value
+has dynamic scope. When CMake starts processing commands in a source file
it sets this variable to the directory where this file is located.
When CMake finishes processing commands from the file it restores the
previous value. Therefore the value of the variable inside a macro or
@@ -14,4 +14,4 @@ function is the directory of the file invoking the bottom-most entry
on the call stack, not the directory of the file containing the macro
or function definition.
-See also CMAKE_CURRENT_LIST_FILE.
+See also :variable:`CMAKE_CURRENT_LIST_FILE`.
diff --git a/Help/variable/CMAKE_CURRENT_LIST_FILE.rst b/Help/variable/CMAKE_CURRENT_LIST_FILE.rst
index 910d7b4..84b0eee 100644
--- a/Help/variable/CMAKE_CURRENT_LIST_FILE.rst
+++ b/Help/variable/CMAKE_CURRENT_LIST_FILE.rst
@@ -12,4 +12,4 @@ value. Therefore the value of the variable inside a macro or function
is the file invoking the bottom-most entry on the call stack, not the
file containing the macro or function definition.
-See also CMAKE_PARENT_LIST_FILE.
+See also :variable:`CMAKE_PARENT_LIST_FILE`.
diff --git a/Help/variable/CMAKE_CXX_COMPILE_FEATURES.rst b/Help/variable/CMAKE_CXX_COMPILE_FEATURES.rst
index f003227..5c59f95 100644
--- a/Help/variable/CMAKE_CXX_COMPILE_FEATURES.rst
+++ b/Help/variable/CMAKE_CXX_COMPILE_FEATURES.rst
@@ -4,8 +4,8 @@ CMAKE_CXX_COMPILE_FEATURES
List of features known to the C++ compiler
These features are known to be available for use with the C++ compiler. This
-list is a subset of the features listed in the :prop_gbl:`CMAKE_CXX_KNOWN_FEATURES`
-global property.
+list is a subset of the features listed in the
+:prop_gbl:`CMAKE_CXX_KNOWN_FEATURES` global property.
See the :manual:`cmake-compile-features(7)` manual for information on
compile features and a list of supported compilers.
diff --git a/Help/variable/CMAKE_CXX_EXTENSIONS.rst b/Help/variable/CMAKE_CXX_EXTENSIONS.rst
index b14d753..4a92425 100644
--- a/Help/variable/CMAKE_CXX_EXTENSIONS.rst
+++ b/Help/variable/CMAKE_CXX_EXTENSIONS.rst
@@ -1,7 +1,7 @@
CMAKE_CXX_EXTENSIONS
--------------------
-Default value for ``CXX_EXTENSIONS`` property of targets.
+Default value for :prop_tgt:`CXX_EXTENSIONS` property of targets.
This variable is used to initialize the :prop_tgt:`CXX_EXTENSIONS`
property on all targets. See that target property for additional
diff --git a/Help/variable/CMAKE_CXX_STANDARD.rst b/Help/variable/CMAKE_CXX_STANDARD.rst
index 2bc4525..8a8bdff 100644
--- a/Help/variable/CMAKE_CXX_STANDARD.rst
+++ b/Help/variable/CMAKE_CXX_STANDARD.rst
@@ -1,7 +1,7 @@
CMAKE_CXX_STANDARD
------------------
-Default value for ``CXX_STANDARD`` property of targets.
+Default value for :prop_tgt:`CXX_STANDARD` property of targets.
This variable is used to initialize the :prop_tgt:`CXX_STANDARD`
property on all targets. See that target property for additional
diff --git a/Help/variable/CMAKE_CXX_STANDARD_REQUIRED.rst b/Help/variable/CMAKE_CXX_STANDARD_REQUIRED.rst
index 14ffcd1..4c71058 100644
--- a/Help/variable/CMAKE_CXX_STANDARD_REQUIRED.rst
+++ b/Help/variable/CMAKE_CXX_STANDARD_REQUIRED.rst
@@ -1,7 +1,7 @@
CMAKE_CXX_STANDARD_REQUIRED
---------------------------
-Default value for ``CXX_STANDARD_REQUIRED`` property of targets.
+Default value for :prop_tgt:`CXX_STANDARD_REQUIRED` property of targets.
This variable is used to initialize the :prop_tgt:`CXX_STANDARD_REQUIRED`
property on all targets. See that target property for additional
diff --git a/Help/variable/CMAKE_C_COMPILE_FEATURES.rst b/Help/variable/CMAKE_C_COMPILE_FEATURES.rst
index df66eae..8d1eca0 100644
--- a/Help/variable/CMAKE_C_COMPILE_FEATURES.rst
+++ b/Help/variable/CMAKE_C_COMPILE_FEATURES.rst
@@ -4,8 +4,8 @@ CMAKE_C_COMPILE_FEATURES
List of features known to the C compiler
These features are known to be available for use with the C compiler. This
-list is a subset of the features listed in the :prop_gbl:`CMAKE_C_KNOWN_FEATURES`
-global property.
+list is a subset of the features listed in the
+:prop_gbl:`CMAKE_C_KNOWN_FEATURES` global property.
See the :manual:`cmake-compile-features(7)` manual for information on
compile features and a list of supported compilers.
diff --git a/Help/variable/CMAKE_C_EXTENSIONS.rst b/Help/variable/CMAKE_C_EXTENSIONS.rst
index 25bec12..fa510d4 100644
--- a/Help/variable/CMAKE_C_EXTENSIONS.rst
+++ b/Help/variable/CMAKE_C_EXTENSIONS.rst
@@ -1,7 +1,7 @@
CMAKE_C_EXTENSIONS
------------------
-Default value for ``C_EXTENSIONS`` property of targets.
+Default value for :prop_tgt:`C_EXTENSIONS` property of targets.
This variable is used to initialize the :prop_tgt:`C_EXTENSIONS`
property on all targets. See that target property for additional
diff --git a/Help/variable/CMAKE_C_STANDARD.rst b/Help/variable/CMAKE_C_STANDARD.rst
index 2eb4e43..b55e00c 100644
--- a/Help/variable/CMAKE_C_STANDARD.rst
+++ b/Help/variable/CMAKE_C_STANDARD.rst
@@ -1,7 +1,7 @@
CMAKE_C_STANDARD
----------------
-Default value for ``C_STANDARD`` property of targets.
+Default value for :prop_tgt:`C_STANDARD` property of targets.
This variable is used to initialize the :prop_tgt:`C_STANDARD`
property on all targets. See that target property for additional
diff --git a/Help/variable/CMAKE_C_STANDARD_REQUIRED.rst b/Help/variable/CMAKE_C_STANDARD_REQUIRED.rst
index 5e415da..7f70f6e 100644
--- a/Help/variable/CMAKE_C_STANDARD_REQUIRED.rst
+++ b/Help/variable/CMAKE_C_STANDARD_REQUIRED.rst
@@ -1,7 +1,7 @@
CMAKE_C_STANDARD_REQUIRED
-------------------------
-Default value for ``C_STANDARD_REQUIRED`` property of targets.
+Default value for :prop_tgt:`C_STANDARD_REQUIRED` property of targets.
This variable is used to initialize the :prop_tgt:`C_STANDARD_REQUIRED`
property on all targets. See that target property for additional
diff --git a/Help/variable/CMAKE_DEBUG_POSTFIX.rst b/Help/variable/CMAKE_DEBUG_POSTFIX.rst
index fde24b2..08577a5 100644
--- a/Help/variable/CMAKE_DEBUG_POSTFIX.rst
+++ b/Help/variable/CMAKE_DEBUG_POSTFIX.rst
@@ -1,7 +1,7 @@
CMAKE_DEBUG_POSTFIX
-------------------
-See variable CMAKE_<CONFIG>_POSTFIX.
+See variable :variable:`CMAKE_<CONFIG>_POSTFIX`.
This variable is a special case of the more-general
-CMAKE_<CONFIG>_POSTFIX variable for the DEBUG configuration.
+:variable:`CMAKE_<CONFIG>_POSTFIX` variable for the `DEBUG` configuration.
diff --git a/Help/variable/CMAKE_DEBUG_TARGET_PROPERTIES.rst b/Help/variable/CMAKE_DEBUG_TARGET_PROPERTIES.rst
index e200b86..513276e 100644
--- a/Help/variable/CMAKE_DEBUG_TARGET_PROPERTIES.rst
+++ b/Help/variable/CMAKE_DEBUG_TARGET_PROPERTIES.rst
@@ -9,6 +9,6 @@ only be used when evaluating the :prop_tgt:`INCLUDE_DIRECTORIES`,
:prop_tgt:`COMPILE_DEFINITIONS`, :prop_tgt:`COMPILE_OPTIONS`,
:prop_tgt:`AUTOUIC_OPTIONS`, :prop_tgt:`SOURCES`, :prop_tgt:`COMPILE_FEATURES`,
:prop_tgt:`POSITION_INDEPENDENT_CODE` target properties and any other property
-listed in :prop_tgt:`COMPATIBLE_INTERFACE_STRING` and other ``COMPATIBLE_INTERFACE_``
-properties. It outputs an origin for each entry in the target property.
-Default is unset.
+listed in :prop_tgt:`COMPATIBLE_INTERFACE_STRING` and other
+``COMPATIBLE_INTERFACE_`` properties. It outputs an origin for each entry in
+the target property. Default is unset.
diff --git a/Help/variable/CMAKE_DISABLE_FIND_PACKAGE_PackageName.rst b/Help/variable/CMAKE_DISABLE_FIND_PACKAGE_PackageName.rst
index bcb277c..ed60020 100644
--- a/Help/variable/CMAKE_DISABLE_FIND_PACKAGE_PackageName.rst
+++ b/Help/variable/CMAKE_DISABLE_FIND_PACKAGE_PackageName.rst
@@ -1,10 +1,11 @@
CMAKE_DISABLE_FIND_PACKAGE_<PackageName>
----------------------------------------
-Variable for disabling find_package() calls.
+Variable for disabling :command:`find_package` calls.
-Every non-REQUIRED find_package() call in a project can be disabled by
-setting the variable CMAKE_DISABLE_FIND_PACKAGE_<PackageName> to TRUE.
+Every non-``REQUIRED`` :command:`find_package` call in a project can be
+disabled by setting the variable
+``CMAKE_DISABLE_FIND_PACKAGE_<PackageName>`` to ``TRUE``.
This can be used to build a project without an optional package,
although that package is installed.
@@ -12,4 +13,4 @@ This switch should be used during the initial CMake run. Otherwise if
the package has already been found in a previous CMake run, the
variables which have been stored in the cache will still be there. In
that case it is recommended to remove the cache variables for this
-package from the cache using the cache editor or cmake -U
+package from the cache using the cache editor or :manual:`cmake(1)` ``-U``
diff --git a/Help/variable/CMAKE_DL_LIBS.rst b/Help/variable/CMAKE_DL_LIBS.rst
index cae4565..1fe7641 100644
--- a/Help/variable/CMAKE_DL_LIBS.rst
+++ b/Help/variable/CMAKE_DL_LIBS.rst
@@ -1,7 +1,7 @@
CMAKE_DL_LIBS
-------------
-Name of library containing dlopen and dlcose.
+Name of library containing ``dlopen`` and ``dlcose``.
-The name of the library that has dlopen and dlclose in it, usually
--ldl on most UNIX machines.
+The name of the library that has ``dlopen`` and ``dlclose`` in it, usually
+``-ldl`` on most UNIX machines.
diff --git a/Help/variable/CMAKE_EDIT_COMMAND.rst b/Help/variable/CMAKE_EDIT_COMMAND.rst
index 562aa0b..2f4ab1f 100644
--- a/Help/variable/CMAKE_EDIT_COMMAND.rst
+++ b/Help/variable/CMAKE_EDIT_COMMAND.rst
@@ -1,8 +1,8 @@
CMAKE_EDIT_COMMAND
------------------
-Full path to cmake-gui or ccmake. Defined only for Makefile generators
-when not using an "extra" generator for an IDE.
+Full path to :manual:`cmake-gui(1)` or :manual:`ccmake(1)`. Defined only for
+:ref:`Makefile Generators` when not using an "extra" generator for an IDE.
This is the full path to the CMake executable that can graphically
-edit the cache. For example, cmake-gui or ccmake.
+edit the cache. For example, :manual:`cmake-gui(1)` or :manual:`ccmake(1)`.
diff --git a/Help/variable/CMAKE_ERROR_DEPRECATED.rst b/Help/variable/CMAKE_ERROR_DEPRECATED.rst
index 43ab282..277a4cc 100644
--- a/Help/variable/CMAKE_ERROR_DEPRECATED.rst
+++ b/Help/variable/CMAKE_ERROR_DEPRECATED.rst
@@ -3,6 +3,6 @@ CMAKE_ERROR_DEPRECATED
Whether to issue deprecation errors for macros and functions.
-If TRUE, this can be used by macros and functions to issue fatal
+If ``TRUE``, this can be used by macros and functions to issue fatal
errors when deprecated macros or functions are used. This variable is
-FALSE by default.
+``FALSE`` by default.
diff --git a/Help/variable/CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION.rst b/Help/variable/CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION.rst
index 651d68d..38e9b7b 100644
--- a/Help/variable/CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION.rst
+++ b/Help/variable/CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION.rst
@@ -1,9 +1,10 @@
CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION
-------------------------------------------
-Ask cmake_install.cmake script to error out as soon as a file with absolute INSTALL DESTINATION is encountered.
+Ask ``cmake_install.cmake`` script to error out as soon as a file with
+absolute ``INSTALL DESTINATION`` is encountered.
The fatal error is emitted before the installation of the offending
file takes place. This variable is used by CMake-generated
-cmake_install.cmake scripts. If one sets this variable to ON while
+``cmake_install.cmake`` scripts. If one sets this variable to ``ON`` while
running the script, it may get fatal error messages from the script.
diff --git a/Help/variable/CMAKE_EXECUTABLE_SUFFIX.rst b/Help/variable/CMAKE_EXECUTABLE_SUFFIX.rst
index 45c313c..356590f 100644
--- a/Help/variable/CMAKE_EXECUTABLE_SUFFIX.rst
+++ b/Help/variable/CMAKE_EXECUTABLE_SUFFIX.rst
@@ -3,7 +3,7 @@ CMAKE_EXECUTABLE_SUFFIX
The suffix for executables on this platform.
-The suffix to use for the end of an executable filename if any, .exe
+The suffix to use for the end of an executable filename if any, ``.exe``
on Windows.
-CMAKE_EXECUTABLE_SUFFIX_<LANG> overrides this for language <LANG>.
+``CMAKE_EXECUTABLE_SUFFIX_<LANG>`` overrides this for language ``<LANG>``.
diff --git a/Help/variable/CMAKE_EXE_LINKER_FLAGS_CONFIG.rst b/Help/variable/CMAKE_EXE_LINKER_FLAGS_CONFIG.rst
index dcaf300..0cd8113 100644
--- a/Help/variable/CMAKE_EXE_LINKER_FLAGS_CONFIG.rst
+++ b/Help/variable/CMAKE_EXE_LINKER_FLAGS_CONFIG.rst
@@ -3,5 +3,5 @@ CMAKE_EXE_LINKER_FLAGS_<CONFIG>
Flags to be used when linking an executable.
-Same as CMAKE_C_FLAGS_* but used by the linker when creating
+Same as ``CMAKE_C_FLAGS_*`` but used by the linker when creating
executables.
diff --git a/Help/variable/CMAKE_EXTRA_GENERATOR.rst b/Help/variable/CMAKE_EXTRA_GENERATOR.rst
index 71aec92..4d513e4 100644
--- a/Help/variable/CMAKE_EXTRA_GENERATOR.rst
+++ b/Help/variable/CMAKE_EXTRA_GENERATOR.rst
@@ -1,9 +1,10 @@
CMAKE_EXTRA_GENERATOR
---------------------
-The extra generator used to build the project.
+The extra generator used to build the project. See
+:manual:`cmake-generators(7)`.
When using the Eclipse, CodeBlocks or KDevelop generators, CMake
-generates Makefiles (CMAKE_GENERATOR) and additionally project files
-for the respective IDE. This IDE project file generator is stored in
-CMAKE_EXTRA_GENERATOR (e.g. "Eclipse CDT4").
+generates Makefiles (:variable:`CMAKE_GENERATOR`) and additionally project
+files for the respective IDE. This IDE project file generator is stored in
+``CMAKE_EXTRA_GENERATOR`` (e.g. ``Eclipse CDT4``).
diff --git a/Help/variable/CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES.rst b/Help/variable/CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES.rst
index 6187a7a..a130adb 100644
--- a/Help/variable/CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES.rst
+++ b/Help/variable/CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES.rst
@@ -4,6 +4,6 @@ CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES
Additional suffixes for shared libraries.
Extensions for shared libraries other than that specified by
-CMAKE_SHARED_LIBRARY_SUFFIX, if any. CMake uses this to recognize
+:variable:`CMAKE_SHARED_LIBRARY_SUFFIX`, if any. CMake uses this to recognize
external shared library files during analysis of libraries linked by a
target.
diff --git a/Help/variable/CMAKE_FIND_LIBRARY_PREFIXES.rst b/Help/variable/CMAKE_FIND_LIBRARY_PREFIXES.rst
index 1a9e7ce..58354b2 100644
--- a/Help/variable/CMAKE_FIND_LIBRARY_PREFIXES.rst
+++ b/Help/variable/CMAKE_FIND_LIBRARY_PREFIXES.rst
@@ -4,6 +4,6 @@ CMAKE_FIND_LIBRARY_PREFIXES
Prefixes to prepend when looking for libraries.
This specifies what prefixes to add to library names when the
-find_library command looks for libraries. On UNIX systems this is
-typically lib, meaning that when trying to find the foo library it
-will look for libfoo.
+:command:`find_library` command looks for libraries. On UNIX systems this is
+typically ``lib``, meaning that when trying to find the ``foo`` library it
+will look for ``libfoo``.
diff --git a/Help/variable/CMAKE_FIND_LIBRARY_SUFFIXES.rst b/Help/variable/CMAKE_FIND_LIBRARY_SUFFIXES.rst
index c533909..4a64e33 100644
--- a/Help/variable/CMAKE_FIND_LIBRARY_SUFFIXES.rst
+++ b/Help/variable/CMAKE_FIND_LIBRARY_SUFFIXES.rst
@@ -4,6 +4,6 @@ CMAKE_FIND_LIBRARY_SUFFIXES
Suffixes to append when looking for libraries.
This specifies what suffixes to add to library names when the
-find_library command looks for libraries. On Windows systems this is
-typically .lib and .dll, meaning that when trying to find the foo
-library it will look for foo.dll etc.
+:command:`find_library` command looks for libraries. On Windows systems this
+is typically ``.lib`` and ``.dll``, meaning that when trying to find the
+``foo`` library it will look for ``foo.dll`` etc.
diff --git a/Help/variable/CMAKE_FIND_NO_INSTALL_PREFIX.rst b/Help/variable/CMAKE_FIND_NO_INSTALL_PREFIX.rst
index 70d920b..c49d264 100644
--- a/Help/variable/CMAKE_FIND_NO_INSTALL_PREFIX.rst
+++ b/Help/variable/CMAKE_FIND_NO_INSTALL_PREFIX.rst
@@ -8,8 +8,8 @@ CMake adds the :variable:`CMAKE_INSTALL_PREFIX` and the
:variable:`CMAKE_SYSTEM_PREFIX_PATH` by default. This variable may be set
on the command line to control that behavior.
-Set :variable:`CMAKE_FIND_NO_INSTALL_PREFIX` to TRUE to tell find_package not
-to search in the :variable:`CMAKE_INSTALL_PREFIX` or
-:variable:`CMAKE_STAGING_PREFIX` by default. Note that the
+Set ``CMAKE_FIND_NO_INSTALL_PREFIX`` to ``TRUE`` to tell
+:command:`find_package` not to search in the :variable:`CMAKE_INSTALL_PREFIX`
+or :variable:`CMAKE_STAGING_PREFIX` by default. Note that the
prefix may still be searched for other reasons, such as being the same prefix
as the CMake installation, or for being a built-in system prefix.
diff --git a/Help/variable/CMAKE_FIND_PACKAGE_WARN_NO_MODULE.rst b/Help/variable/CMAKE_FIND_PACKAGE_WARN_NO_MODULE.rst
index 5d7599c..f1116bb 100644
--- a/Help/variable/CMAKE_FIND_PACKAGE_WARN_NO_MODULE.rst
+++ b/Help/variable/CMAKE_FIND_PACKAGE_WARN_NO_MODULE.rst
@@ -1,19 +1,19 @@
CMAKE_FIND_PACKAGE_WARN_NO_MODULE
---------------------------------
-Tell find_package to warn if called without an explicit mode.
+Tell :command:`find_package` to warn if called without an explicit mode.
-If find_package is called without an explicit mode option (MODULE,
-CONFIG or NO_MODULE) and no Find<pkg>.cmake module is in
-CMAKE_MODULE_PATH then CMake implicitly assumes that the caller
-intends to search for a package configuration file. If no package
+If :command:`find_package` is called without an explicit mode option
+(``MODULE``, ``CONFIG``, or ``NO_MODULE``) and no ``Find<pkg>.cmake`` module
+is in :variable:`CMAKE_MODULE_PATH` then CMake implicitly assumes that the
+caller intends to search for a package configuration file. If no package
configuration file is found then the wording of the failure message
must account for both the case that the package is really missing and
the case that the project has a bug and failed to provide the intended
Find module. If instead the caller specifies an explicit mode option
then the failure message can be more specific.
-Set CMAKE_FIND_PACKAGE_WARN_NO_MODULE to TRUE to tell find_package to
-warn when it implicitly assumes Config mode. This helps developers
-enforce use of an explicit mode in all calls to find_package within a
-project.
+Set ``CMAKE_FIND_PACKAGE_WARN_NO_MODULE`` to ``TRUE`` to tell
+:command:`find_package` to warn when it implicitly assumes Config mode. This
+helps developers enforce use of an explicit mode in all calls to
+:command:`find_package` within a project.
diff --git a/Help/variable/CMAKE_FIND_ROOT_PATH.rst b/Help/variable/CMAKE_FIND_ROOT_PATH.rst
index ccf5234..ba2cf31 100644
--- a/Help/variable/CMAKE_FIND_ROOT_PATH.rst
+++ b/Help/variable/CMAKE_FIND_ROOT_PATH.rst
@@ -4,5 +4,5 @@ CMAKE_FIND_ROOT_PATH
:ref:`;-list <CMake Language Lists>` of root paths to search on the filesystem.
This variable is most useful when cross-compiling. CMake uses the paths in
-this list as alternative roots to find filesystem items with :command:`find_package`,
-:command:`find_library` etc.
+this list as alternative roots to find filesystem items with
+:command:`find_package`, :command:`find_library` etc.
diff --git a/Help/variable/CMAKE_Fortran_FORMAT.rst b/Help/variable/CMAKE_Fortran_FORMAT.rst
index c0e971c..1406e59 100644
--- a/Help/variable/CMAKE_Fortran_FORMAT.rst
+++ b/Help/variable/CMAKE_Fortran_FORMAT.rst
@@ -1,7 +1,7 @@
CMAKE_Fortran_FORMAT
--------------------
-Set to FIXED or FREE to indicate the Fortran source layout.
+Set to ``FIXED`` or ``FREE`` to indicate the Fortran source layout.
-This variable is used to initialize the Fortran_FORMAT property on all
-the targets. See that target property for additional information.
+This variable is used to initialize the :prop_tgt:`Fortran_FORMAT` property on
+all the targets. See that target property for additional information.
diff --git a/Help/variable/CMAKE_Fortran_MODDIR_DEFAULT.rst b/Help/variable/CMAKE_Fortran_MODDIR_DEFAULT.rst
index a8dfcdf..5aeab07 100644
--- a/Help/variable/CMAKE_Fortran_MODDIR_DEFAULT.rst
+++ b/Help/variable/CMAKE_Fortran_MODDIR_DEFAULT.rst
@@ -3,6 +3,6 @@ CMAKE_Fortran_MODDIR_DEFAULT
Fortran default module output directory.
-Most Fortran compilers write .mod files to the current working
-directory. For those that do not, this is set to "." and used when
-the Fortran_MODULE_DIRECTORY target property is not set.
+Most Fortran compilers write ``.mod`` files to the current working
+directory. For those that do not, this is set to ``.`` and used when
+the :prop_tgt:`Fortran_MODULE_DIRECTORY` target property is not set.
diff --git a/Help/variable/CMAKE_Fortran_MODDIR_FLAG.rst b/Help/variable/CMAKE_Fortran_MODDIR_FLAG.rst
index 4b32df3..1da55ca 100644
--- a/Help/variable/CMAKE_Fortran_MODDIR_FLAG.rst
+++ b/Help/variable/CMAKE_Fortran_MODDIR_FLAG.rst
@@ -4,4 +4,4 @@ CMAKE_Fortran_MODDIR_FLAG
Fortran flag for module output directory.
This stores the flag needed to pass the value of the
-Fortran_MODULE_DIRECTORY target property to the compiler.
+:prop_tgt:`Fortran_MODULE_DIRECTORY` target property to the compiler.
diff --git a/Help/variable/CMAKE_Fortran_MODOUT_FLAG.rst b/Help/variable/CMAKE_Fortran_MODOUT_FLAG.rst
index a232213..2f83880 100644
--- a/Help/variable/CMAKE_Fortran_MODOUT_FLAG.rst
+++ b/Help/variable/CMAKE_Fortran_MODOUT_FLAG.rst
@@ -3,5 +3,5 @@ CMAKE_Fortran_MODOUT_FLAG
Fortran flag to enable module output.
-Most Fortran compilers write .mod files out by default. For others,
+Most Fortran compilers write ``.mod`` files out by default. For others,
this stores the flag needed to enable module output.
diff --git a/Help/variable/CMAKE_Fortran_MODULE_DIRECTORY.rst b/Help/variable/CMAKE_Fortran_MODULE_DIRECTORY.rst
index b1d49d8..3c7edc1 100644
--- a/Help/variable/CMAKE_Fortran_MODULE_DIRECTORY.rst
+++ b/Help/variable/CMAKE_Fortran_MODULE_DIRECTORY.rst
@@ -3,6 +3,6 @@ CMAKE_Fortran_MODULE_DIRECTORY
Fortran module output directory.
-This variable is used to initialize the Fortran_MODULE_DIRECTORY
+This variable is used to initialize the :prop_tgt:`Fortran_MODULE_DIRECTORY`
property on all the targets. See that target property for additional
information.
diff --git a/Help/variable/CMAKE_GENERATOR.rst b/Help/variable/CMAKE_GENERATOR.rst
index a4e70a5..3f6ebc1 100644
--- a/Help/variable/CMAKE_GENERATOR.rst
+++ b/Help/variable/CMAKE_GENERATOR.rst
@@ -1,7 +1,7 @@
CMAKE_GENERATOR
---------------
-The generator used to build the project.
+The generator used to build the project. See :manual:`cmake-generators(7)`.
The name of the generator that is being used to generate the build
-files. (e.g. "Unix Makefiles", "Visual Studio 6", etc.)
+files. (e.g. ``Unix Makefiles``, ``Visual Studio 6``, etc.)
diff --git a/Help/variable/CMAKE_GENERATOR_PLATFORM.rst b/Help/variable/CMAKE_GENERATOR_PLATFORM.rst
index 5559eb7..a5c284a 100644
--- a/Help/variable/CMAKE_GENERATOR_PLATFORM.rst
+++ b/Help/variable/CMAKE_GENERATOR_PLATFORM.rst
@@ -5,8 +5,8 @@ Generator-specific target platform name specified by user.
Some CMake generators support a target platform name to be given
to the native build system to choose a compiler toolchain.
-If the user specifies a platform name (e.g. via the cmake -A option)
-the value will be available in this variable.
+If the user specifies a platform name (e.g. via the :manual:`cmake(1)` ``-A``
+option) the value will be available in this variable.
The value of this variable should never be modified by project code.
A toolchain file specified by the :variable:`CMAKE_TOOLCHAIN_FILE`
diff --git a/Help/variable/CMAKE_GENERATOR_TOOLSET.rst b/Help/variable/CMAKE_GENERATOR_TOOLSET.rst
index 9ccc8b3..89abe54 100644
--- a/Help/variable/CMAKE_GENERATOR_TOOLSET.rst
+++ b/Help/variable/CMAKE_GENERATOR_TOOLSET.rst
@@ -5,8 +5,8 @@ Native build system toolset name specified by user.
Some CMake generators support a toolset name to be given to the native
build system to choose a compiler. If the user specifies a toolset
-name (e.g. via the cmake -T option) the value will be available in
-this variable.
+name (e.g. via the :manual:`cmake(1)` ``-T`` option) the value will be
+available in this variable.
The value of this variable should never be modified by project code.
A toolchain file specified by the :variable:`CMAKE_TOOLCHAIN_FILE`
diff --git a/Help/variable/CMAKE_GNUtoMS.rst b/Help/variable/CMAKE_GNUtoMS.rst
index e253f59..9c0f59e 100644
--- a/Help/variable/CMAKE_GNUtoMS.rst
+++ b/Help/variable/CMAKE_GNUtoMS.rst
@@ -1,8 +1,8 @@
CMAKE_GNUtoMS
-------------
-Convert GNU import libraries (.dll.a) to MS format (.lib).
+Convert GNU import libraries (``.dll.a``) to MS format (``.lib``).
-This variable is used to initialize the GNUtoMS property on targets
-when they are created. See that target property for additional
+This variable is used to initialize the :prop_tgt:`GNUtoMS` property on
+targets when they are created. See that target property for additional
information.
diff --git a/Help/variable/CMAKE_HOST_APPLE.rst b/Help/variable/CMAKE_HOST_APPLE.rst
index d4b8483..ac7b030 100644
--- a/Help/variable/CMAKE_HOST_APPLE.rst
+++ b/Help/variable/CMAKE_HOST_APPLE.rst
@@ -1,6 +1,6 @@
CMAKE_HOST_APPLE
----------------
-True for Apple OS X operating systems.
+``True`` for Apple OS X operating systems.
-Set to true when the host system is Apple OS X.
+Set to ``true`` when the host system is Apple OS X.
diff --git a/Help/variable/CMAKE_HOST_SYSTEM_NAME.rst b/Help/variable/CMAKE_HOST_SYSTEM_NAME.rst
index a221de9..e5e6f67 100644
--- a/Help/variable/CMAKE_HOST_SYSTEM_NAME.rst
+++ b/Help/variable/CMAKE_HOST_SYSTEM_NAME.rst
@@ -4,5 +4,5 @@ CMAKE_HOST_SYSTEM_NAME
Name of the OS CMake is running on.
On systems that have the uname command, this variable is set to the
-output of uname -s. ``Linux``, ``Windows``, and ``Darwin`` for Mac OS X
+output of ``uname -s``. ``Linux``, ``Windows``, and ``Darwin`` for Mac OS X
are the values found on the big three operating systems.
diff --git a/Help/variable/CMAKE_HOST_SYSTEM_PROCESSOR.rst b/Help/variable/CMAKE_HOST_SYSTEM_PROCESSOR.rst
index 790565a..ba8a850 100644
--- a/Help/variable/CMAKE_HOST_SYSTEM_PROCESSOR.rst
+++ b/Help/variable/CMAKE_HOST_SYSTEM_PROCESSOR.rst
@@ -3,6 +3,6 @@ CMAKE_HOST_SYSTEM_PROCESSOR
The name of the CPU CMake is running on.
-On systems that support uname, this variable is set to the output of
-uname -p, on windows it is set to the value of the environment variable
+On systems that support ``uname``, this variable is set to the output of
+``uname -p``. On Windows it is set to the value of the environment variable
``PROCESSOR_ARCHITECTURE``.
diff --git a/Help/variable/CMAKE_HOST_SYSTEM_VERSION.rst b/Help/variable/CMAKE_HOST_SYSTEM_VERSION.rst
index e7e0052..ed23070 100644
--- a/Help/variable/CMAKE_HOST_SYSTEM_VERSION.rst
+++ b/Help/variable/CMAKE_HOST_SYSTEM_VERSION.rst
@@ -4,5 +4,5 @@ CMAKE_HOST_SYSTEM_VERSION
The OS version CMake is running on.
A numeric version string for the system. On systems that support
-uname, this variable is set to the output of uname -r. On other
+``uname``, this variable is set to the output of ``uname -r``. On other
systems this is set to major-minor version numbers.
diff --git a/Help/variable/CMAKE_HOST_UNIX.rst b/Help/variable/CMAKE_HOST_UNIX.rst
index bbefba7..817a957 100644
--- a/Help/variable/CMAKE_HOST_UNIX.rst
+++ b/Help/variable/CMAKE_HOST_UNIX.rst
@@ -1,7 +1,7 @@
CMAKE_HOST_UNIX
---------------
-True for UNIX and UNIX like operating systems.
+``True`` for UNIX and UNIX like operating systems.
-Set to true when the host system is UNIX or UNIX like (i.e. APPLE and
+Set to ``true`` when the host system is UNIX or UNIX like (i.e. APPLE and
CYGWIN).
diff --git a/Help/variable/CMAKE_HOST_WIN32.rst b/Help/variable/CMAKE_HOST_WIN32.rst
index 92ee456..0e4c891 100644
--- a/Help/variable/CMAKE_HOST_WIN32.rst
+++ b/Help/variable/CMAKE_HOST_WIN32.rst
@@ -1,6 +1,6 @@
CMAKE_HOST_WIN32
----------------
-True on windows systems, including win64.
+``True`` on Windows systems, including Win64.
-Set to true when the host system is Windows and on Cygwin.
+Set to ``true`` when the host system is Windows and on Cygwin.
diff --git a/Help/variable/CMAKE_IMPORT_LIBRARY_PREFIX.rst b/Help/variable/CMAKE_IMPORT_LIBRARY_PREFIX.rst
index 1d16a37..1561a1d 100644
--- a/Help/variable/CMAKE_IMPORT_LIBRARY_PREFIX.rst
+++ b/Help/variable/CMAKE_IMPORT_LIBRARY_PREFIX.rst
@@ -6,4 +6,4 @@ The prefix for import libraries that you link to.
The prefix to use for the name of an import library if used on this
platform.
-CMAKE_IMPORT_LIBRARY_PREFIX_<LANG> overrides this for language <LANG>.
+``CMAKE_IMPORT_LIBRARY_PREFIX_<LANG>`` overrides this for language ``<LANG>``.
diff --git a/Help/variable/CMAKE_IMPORT_LIBRARY_SUFFIX.rst b/Help/variable/CMAKE_IMPORT_LIBRARY_SUFFIX.rst
index c16825e..11aeab7 100644
--- a/Help/variable/CMAKE_IMPORT_LIBRARY_SUFFIX.rst
+++ b/Help/variable/CMAKE_IMPORT_LIBRARY_SUFFIX.rst
@@ -6,4 +6,4 @@ The suffix for import libraries that you link to.
The suffix to use for the end of an import library filename if used on
this platform.
-CMAKE_IMPORT_LIBRARY_SUFFIX_<LANG> overrides this for language <LANG>.
+``CMAKE_IMPORT_LIBRARY_SUFFIX_<LANG>`` overrides this for language ``<LANG>``.
diff --git a/Help/variable/CMAKE_INCLUDE_CURRENT_DIR.rst b/Help/variable/CMAKE_INCLUDE_CURRENT_DIR.rst
index 79f3952..6eea322 100644
--- a/Help/variable/CMAKE_INCLUDE_CURRENT_DIR.rst
+++ b/Help/variable/CMAKE_INCLUDE_CURRENT_DIR.rst
@@ -3,11 +3,11 @@ CMAKE_INCLUDE_CURRENT_DIR
Automatically add the current source- and build directories to the include path.
-If this variable is enabled, CMake automatically adds in each
-directory ${CMAKE_CURRENT_SOURCE_DIR} and ${CMAKE_CURRENT_BINARY_DIR}
-to the include path for this directory. These additional include
+If this variable is enabled, CMake automatically adds
+:variable:`CMAKE_CURRENT_SOURCE_DIR` and :variable:`CMAKE_CURRENT_BINARY_DIR`
+to the include path for each directory. These additional include
directories do not propagate down to subdirectories. This is useful
mainly for out-of-source builds, where files generated into the build
tree are included by files located in the source tree.
-By default CMAKE_INCLUDE_CURRENT_DIR is OFF.
+By default ``CMAKE_INCLUDE_CURRENT_DIR`` is ``OFF``.
diff --git a/Help/variable/CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE.rst b/Help/variable/CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE.rst
index 948db50..5fc95f0 100644
--- a/Help/variable/CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE.rst
+++ b/Help/variable/CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE.rst
@@ -1,10 +1,12 @@
CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE
--------------------------------------
-Automatically add the current source- and build directories to the INTERFACE_INCLUDE_DIRECTORIES.
+Automatically add the current source- and build directories to the
+:prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` target property.
If this variable is enabled, CMake automatically adds for each shared
library target, static library target, module target and executable
-target, ${CMAKE_CURRENT_SOURCE_DIR} and ${CMAKE_CURRENT_BINARY_DIR} to
-the INTERFACE_INCLUDE_DIRECTORIES.By default
-CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE is OFF.
+target, :variable:`CMAKE_CURRENT_SOURCE_DIR` and
+:variable:`CMAKE_CURRENT_BINARY_DIR` to
+the :prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` target property. By default
+``CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE`` is ``OFF``.
diff --git a/Help/variable/CMAKE_INCLUDE_DIRECTORIES_BEFORE.rst b/Help/variable/CMAKE_INCLUDE_DIRECTORIES_BEFORE.rst
index 3c1fbcf..e0f2a2e 100644
--- a/Help/variable/CMAKE_INCLUDE_DIRECTORIES_BEFORE.rst
+++ b/Help/variable/CMAKE_INCLUDE_DIRECTORIES_BEFORE.rst
@@ -1,8 +1,9 @@
CMAKE_INCLUDE_DIRECTORIES_BEFORE
--------------------------------
-Whether to append or prepend directories by default in :command:`include_directories`.
+Whether to append or prepend directories by default in
+:command:`include_directories`.
This variable affects the default behavior of the :command:`include_directories`
-command. Setting this variable to 'ON' is equivalent to using the BEFORE option
-in all uses of that command.
+command. Setting this variable to ``ON`` is equivalent to using the ``BEFORE``
+option in all uses of that command.
diff --git a/Help/variable/CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE.rst b/Help/variable/CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE.rst
index cbd04d7..37d0a3d 100644
--- a/Help/variable/CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE.rst
+++ b/Help/variable/CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE.rst
@@ -4,5 +4,5 @@ CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE
Whether to force prepending of project include directories.
This variable affects the order of include directories generated in compiler
-command lines. If set to 'ON', it causes the :variable:`CMAKE_SOURCE_DIR` and
-the :variable:`CMAKE_BINARY_DIR` to appear first.
+command lines. If set to ``ON``, it causes the :variable:`CMAKE_SOURCE_DIR`
+and the :variable:`CMAKE_BINARY_DIR` to appear first.
diff --git a/Help/variable/CMAKE_INSTALL_DEFAULT_COMPONENT_NAME.rst b/Help/variable/CMAKE_INSTALL_DEFAULT_COMPONENT_NAME.rst
index 2ad0689..57160f1 100644
--- a/Help/variable/CMAKE_INSTALL_DEFAULT_COMPONENT_NAME.rst
+++ b/Help/variable/CMAKE_INSTALL_DEFAULT_COMPONENT_NAME.rst
@@ -1,9 +1,9 @@
CMAKE_INSTALL_DEFAULT_COMPONENT_NAME
------------------------------------
-Default component used in install() commands.
+Default component used in :command:`install` commands.
-If an install() command is used without the COMPONENT argument, these
-files will be grouped into a default component. The name of this
+If an :command:`install` command is used without the ``COMPONENT`` argument,
+these files will be grouped into a default component. The name of this
default install component will be taken from this variable. It
-defaults to "Unspecified".
+defaults to ``Unspecified``.
diff --git a/Help/variable/CMAKE_INSTALL_NAME_DIR.rst b/Help/variable/CMAKE_INSTALL_NAME_DIR.rst
index 540df6b..961d712 100644
--- a/Help/variable/CMAKE_INSTALL_NAME_DIR.rst
+++ b/Help/variable/CMAKE_INSTALL_NAME_DIR.rst
@@ -3,6 +3,6 @@ CMAKE_INSTALL_NAME_DIR
Mac OS X directory name for installed targets.
-CMAKE_INSTALL_NAME_DIR is used to initialize the INSTALL_NAME_DIR
-property on all targets. See that target property for more
-information.
+``CMAKE_INSTALL_NAME_DIR`` is used to initialize the
+:prop_tgt:`INSTALL_NAME_DIR` property on all targets. See that target
+property for more information.
diff --git a/Help/variable/CMAKE_INSTALL_PREFIX.rst b/Help/variable/CMAKE_INSTALL_PREFIX.rst
index ee9b615..3f3347f 100644
--- a/Help/variable/CMAKE_INSTALL_PREFIX.rst
+++ b/Help/variable/CMAKE_INSTALL_PREFIX.rst
@@ -1,14 +1,14 @@
CMAKE_INSTALL_PREFIX
--------------------
-Install directory used by install.
+Install directory used by :command:`install`.
-If "make install" is invoked or INSTALL is built, this directory is
+If ``make install`` is invoked or ``INSTALL`` is built, this directory is
prepended onto all install directories. This variable defaults to
-/usr/local on UNIX and c:/Program Files on Windows.
+``/usr/local`` on UNIX and ``c:/Program Files`` on Windows.
-On UNIX one can use the DESTDIR mechanism in order to relocate the
-whole installation. DESTDIR means DESTination DIRectory. It is
+On UNIX one can use the ``DESTDIR`` mechanism in order to relocate the
+whole installation. ``DESTDIR`` means DESTination DIRectory. It is
commonly used by makefile users in order to install software at
non-default location. It is usually invoked like this:
@@ -17,16 +17,17 @@ non-default location. It is usually invoked like this:
make DESTDIR=/home/john install
which will install the concerned software using the installation
-prefix, e.g. "/usr/local" prepended with the DESTDIR value which
-finally gives "/home/john/usr/local".
+prefix, e.g. ``/usr/local`` prepended with the ``DESTDIR`` value which
+finally gives ``/home/john/usr/local``.
-WARNING: DESTDIR may not be used on Windows because installation
-prefix usually contains a drive letter like in "C:/Program Files"
+WARNING: ``DESTDIR`` may not be used on Windows because installation
+prefix usually contains a drive letter like in ``C:/Program Files``
which cannot be prepended with some other prefix.
-The installation prefix is also added to CMAKE_SYSTEM_PREFIX_PATH so
-that find_package, find_program, find_library, find_path, and
-find_file will search the prefix for other software.
+The installation prefix is also added to :variable:`CMAKE_SYSTEM_PREFIX_PATH`
+so that :command:`find_package`, :command:`find_program`,
+:command:`find_library`, :command:`find_path`, and :command:`find_file`
+will search the prefix for other software.
.. note::
diff --git a/Help/variable/CMAKE_INSTALL_RPATH.rst b/Help/variable/CMAKE_INSTALL_RPATH.rst
index 0992d57..813d1e0 100644
--- a/Help/variable/CMAKE_INSTALL_RPATH.rst
+++ b/Help/variable/CMAKE_INSTALL_RPATH.rst
@@ -5,4 +5,4 @@ The rpath to use for installed targets.
A semicolon-separated list specifying the rpath to use in installed
targets (for platforms that support it). This is used to initialize
-the target property INSTALL_RPATH for all targets.
+the target property :prop_tgt:`INSTALL_RPATH` for all targets.
diff --git a/Help/variable/CMAKE_INSTALL_RPATH_USE_LINK_PATH.rst b/Help/variable/CMAKE_INSTALL_RPATH_USE_LINK_PATH.rst
index 9277a3b..78148d5 100644
--- a/Help/variable/CMAKE_INSTALL_RPATH_USE_LINK_PATH.rst
+++ b/Help/variable/CMAKE_INSTALL_RPATH_USE_LINK_PATH.rst
@@ -3,7 +3,7 @@ CMAKE_INSTALL_RPATH_USE_LINK_PATH
Add paths to linker search and installed rpath.
-CMAKE_INSTALL_RPATH_USE_LINK_PATH is a boolean that if set to true
+``CMAKE_INSTALL_RPATH_USE_LINK_PATH`` is a boolean that if set to ``true``
will append directories in the linker search path and outside the
-project to the INSTALL_RPATH. This is used to initialize the target
-property INSTALL_RPATH_USE_LINK_PATH for all targets.
+project to the :prop_tgt:`INSTALL_RPATH`. This is used to initialize the
+target property :prop_tgt:`INSTALL_RPATH_USE_LINK_PATH` for all targets.
diff --git a/Help/variable/CMAKE_LANG_ARCHIVE_APPEND.rst b/Help/variable/CMAKE_LANG_ARCHIVE_APPEND.rst
index 2c3abae..ab4ad71 100644
--- a/Help/variable/CMAKE_LANG_ARCHIVE_APPEND.rst
+++ b/Help/variable/CMAKE_LANG_ARCHIVE_APPEND.rst
@@ -4,6 +4,7 @@ CMAKE_<LANG>_ARCHIVE_APPEND
Rule variable to append to a static archive.
This is a rule variable that tells CMake how to append to a static
-archive. It is used in place of CMAKE_<LANG>_CREATE_STATIC_LIBRARY on
-some platforms in order to support large object counts. See also
-CMAKE_<LANG>_ARCHIVE_CREATE and CMAKE_<LANG>_ARCHIVE_FINISH.
+archive. It is used in place of :variable:`CMAKE_<LANG>_CREATE_STATIC_LIBRARY`
+on some platforms in order to support large object counts. See also
+:variable:`CMAKE_<LANG>_ARCHIVE_CREATE` and
+:variable:`CMAKE_<LANG>_ARCHIVE_FINISH`.
diff --git a/Help/variable/CMAKE_LANG_ARCHIVE_CREATE.rst b/Help/variable/CMAKE_LANG_ARCHIVE_CREATE.rst
index f93dd11..fc295af 100644
--- a/Help/variable/CMAKE_LANG_ARCHIVE_CREATE.rst
+++ b/Help/variable/CMAKE_LANG_ARCHIVE_CREATE.rst
@@ -4,6 +4,7 @@ CMAKE_<LANG>_ARCHIVE_CREATE
Rule variable to create a new static archive.
This is a rule variable that tells CMake how to create a static
-archive. It is used in place of CMAKE_<LANG>_CREATE_STATIC_LIBRARY on
-some platforms in order to support large object counts. See also
-CMAKE_<LANG>_ARCHIVE_APPEND and CMAKE_<LANG>_ARCHIVE_FINISH.
+archive. It is used in place of :variable:`CMAKE_<LANG>_CREATE_STATIC_LIBRARY`
+on some platforms in order to support large object counts. See also
+:variable:`CMAKE_<LANG>_ARCHIVE_APPEND` and
+:variable:`CMAKE_<LANG>_ARCHIVE_FINISH`.
diff --git a/Help/variable/CMAKE_LANG_ARCHIVE_FINISH.rst b/Help/variable/CMAKE_LANG_ARCHIVE_FINISH.rst
index fff4128..1bb5d65 100644
--- a/Help/variable/CMAKE_LANG_ARCHIVE_FINISH.rst
+++ b/Help/variable/CMAKE_LANG_ARCHIVE_FINISH.rst
@@ -4,6 +4,7 @@ CMAKE_<LANG>_ARCHIVE_FINISH
Rule variable to finish an existing static archive.
This is a rule variable that tells CMake how to finish a static
-archive. It is used in place of CMAKE_<LANG>_CREATE_STATIC_LIBRARY on
-some platforms in order to support large object counts. See also
-CMAKE_<LANG>_ARCHIVE_CREATE and CMAKE_<LANG>_ARCHIVE_APPEND.
+archive. It is used in place of :variable:`CMAKE_<LANG>_CREATE_STATIC_LIBRARY`
+on some platforms in order to support large object counts. See also
+:variable:`CMAKE_<LANG>_ARCHIVE_CREATE` and
+:variable:`CMAKE_<LANG>_ARCHIVE_APPEND`.
diff --git a/Help/variable/CMAKE_LANG_COMPILER.rst b/Help/variable/CMAKE_LANG_COMPILER.rst
index fffc347..89df495 100644
--- a/Help/variable/CMAKE_LANG_COMPILER.rst
+++ b/Help/variable/CMAKE_LANG_COMPILER.rst
@@ -1,7 +1,7 @@
CMAKE_<LANG>_COMPILER
---------------------
-The full path to the compiler for LANG.
+The full path to the compiler for ``LANG``.
-This is the command that will be used as the <LANG> compiler. Once
+This is the command that will be used as the ``<LANG>`` compiler. Once
set, you can not change this variable.
diff --git a/Help/variable/CMAKE_LANG_COMPILER_EXTERNAL_TOOLCHAIN.rst b/Help/variable/CMAKE_LANG_COMPILER_EXTERNAL_TOOLCHAIN.rst
index 033998d..8bb7cc0 100644
--- a/Help/variable/CMAKE_LANG_COMPILER_EXTERNAL_TOOLCHAIN.rst
+++ b/Help/variable/CMAKE_LANG_COMPILER_EXTERNAL_TOOLCHAIN.rst
@@ -5,9 +5,9 @@ The external toolchain for cross-compiling, if supported.
Some compiler toolchains do not ship their own auxilliary utilities such as
archivers and linkers. The compiler driver may support a command-line argument
-to specify the location of such tools. CMAKE_<LANG>_COMPILER_EXTERNAL_TOOLCHAIN
-may be set to a path to a path to the external toolchain and will be passed
-to the compiler driver if supported.
+to specify the location of such tools.
+``CMAKE_<LANG>_COMPILER_EXTERNAL_TOOLCHAIN`` may be set to a path to a path to
+the external toolchain and will be passed to the compiler driver if supported.
This variable may only be set in a toolchain file specified by
the :variable:`CMAKE_TOOLCHAIN_FILE` variable.
diff --git a/Help/variable/CMAKE_LANG_COMPILER_LOADED.rst b/Help/variable/CMAKE_LANG_COMPILER_LOADED.rst
index 3b8e9aa..9308878 100644
--- a/Help/variable/CMAKE_LANG_COMPILER_LOADED.rst
+++ b/Help/variable/CMAKE_LANG_COMPILER_LOADED.rst
@@ -3,5 +3,5 @@ CMAKE_<LANG>_COMPILER_LOADED
Defined to true if the language is enabled.
-When language <LANG> is enabled by project() or enable_language() this
-variable is defined to 1.
+When language ``<LANG>`` is enabled by :command:`project` or
+:command:`enable_language` this variable is defined to ``1``.
diff --git a/Help/variable/CMAKE_LANG_COMPILE_OBJECT.rst b/Help/variable/CMAKE_LANG_COMPILE_OBJECT.rst
index f43ed6d..ba59cad 100644
--- a/Help/variable/CMAKE_LANG_COMPILE_OBJECT.rst
+++ b/Help/variable/CMAKE_LANG_COMPILE_OBJECT.rst
@@ -4,4 +4,4 @@ CMAKE_<LANG>_COMPILE_OBJECT
Rule variable to compile a single object file.
This is a rule variable that tells CMake how to compile a single
-object file for the language <LANG>.
+object file for the language ``<LANG>``.
diff --git a/Help/variable/CMAKE_LANG_CREATE_SHARED_LIBRARY.rst b/Help/variable/CMAKE_LANG_CREATE_SHARED_LIBRARY.rst
index adf1624..be89f85 100644
--- a/Help/variable/CMAKE_LANG_CREATE_SHARED_LIBRARY.rst
+++ b/Help/variable/CMAKE_LANG_CREATE_SHARED_LIBRARY.rst
@@ -4,4 +4,4 @@ CMAKE_<LANG>_CREATE_SHARED_LIBRARY
Rule variable to create a shared library.
This is a rule variable that tells CMake how to create a shared
-library for the language <LANG>.
+library for the language ``<LANG>``.
diff --git a/Help/variable/CMAKE_LANG_CREATE_SHARED_MODULE.rst b/Help/variable/CMAKE_LANG_CREATE_SHARED_MODULE.rst
index 406b4da..ae5f69d 100644
--- a/Help/variable/CMAKE_LANG_CREATE_SHARED_MODULE.rst
+++ b/Help/variable/CMAKE_LANG_CREATE_SHARED_MODULE.rst
@@ -4,4 +4,4 @@ CMAKE_<LANG>_CREATE_SHARED_MODULE
Rule variable to create a shared module.
This is a rule variable that tells CMake how to create a shared
-library for the language <LANG>.
+library for the language ``<LANG>``.
diff --git a/Help/variable/CMAKE_LANG_CREATE_STATIC_LIBRARY.rst b/Help/variable/CMAKE_LANG_CREATE_STATIC_LIBRARY.rst
index 8114432..0cff200 100644
--- a/Help/variable/CMAKE_LANG_CREATE_STATIC_LIBRARY.rst
+++ b/Help/variable/CMAKE_LANG_CREATE_STATIC_LIBRARY.rst
@@ -4,4 +4,4 @@ CMAKE_<LANG>_CREATE_STATIC_LIBRARY
Rule variable to create a static library.
This is a rule variable that tells CMake how to create a static
-library for the language <LANG>.
+library for the language ``<LANG>``.
diff --git a/Help/variable/CMAKE_LANG_FLAGS.rst b/Help/variable/CMAKE_LANG_FLAGS.rst
index 6aa0a3e..c57d92c 100644
--- a/Help/variable/CMAKE_LANG_FLAGS.rst
+++ b/Help/variable/CMAKE_LANG_FLAGS.rst
@@ -3,4 +3,4 @@ CMAKE_<LANG>_FLAGS
Flags for all build types.
-<LANG> flags used regardless of the value of CMAKE_BUILD_TYPE.
+``<LANG>`` flags used regardless of the value of :variable:`CMAKE_BUILD_TYPE`.
diff --git a/Help/variable/CMAKE_LANG_FLAGS_DEBUG.rst b/Help/variable/CMAKE_LANG_FLAGS_DEBUG.rst
index a727641..a233d4a 100644
--- a/Help/variable/CMAKE_LANG_FLAGS_DEBUG.rst
+++ b/Help/variable/CMAKE_LANG_FLAGS_DEBUG.rst
@@ -1,6 +1,6 @@
CMAKE_<LANG>_FLAGS_DEBUG
------------------------
-Flags for Debug build type or configuration.
+Flags for ``Debug`` build type or configuration.
-<LANG> flags used when CMAKE_BUILD_TYPE is Debug.
+``<LANG>`` flags used when :variable:`CMAKE_BUILD_TYPE` is ``Debug``.
diff --git a/Help/variable/CMAKE_LANG_FLAGS_MINSIZEREL.rst b/Help/variable/CMAKE_LANG_FLAGS_MINSIZEREL.rst
index fbb8516..a9436c1 100644
--- a/Help/variable/CMAKE_LANG_FLAGS_MINSIZEREL.rst
+++ b/Help/variable/CMAKE_LANG_FLAGS_MINSIZEREL.rst
@@ -1,7 +1,7 @@
CMAKE_<LANG>_FLAGS_MINSIZEREL
-----------------------------
-Flags for MinSizeRel build type or configuration.
+Flags for ``MinSizeRel`` build type or configuration.
-<LANG> flags used when CMAKE_BUILD_TYPE is MinSizeRel.Short for
-minimum size release.
+``<LANG>`` flags used when :variable:`CMAKE_BUILD_TYPE` is ``MinSizeRel``
+(short for minimum size release).
diff --git a/Help/variable/CMAKE_LANG_FLAGS_RELEASE.rst b/Help/variable/CMAKE_LANG_FLAGS_RELEASE.rst
index 4b2c926..ffc5d79 100644
--- a/Help/variable/CMAKE_LANG_FLAGS_RELEASE.rst
+++ b/Help/variable/CMAKE_LANG_FLAGS_RELEASE.rst
@@ -1,6 +1,6 @@
CMAKE_<LANG>_FLAGS_RELEASE
--------------------------
-Flags for Release build type or configuration.
+Flags for ``Release`` build type or configuration.
-<LANG> flags used when CMAKE_BUILD_TYPE is Release
+``<LANG>`` flags used when :variable:`CMAKE_BUILD_TYPE` is ``Release``.
diff --git a/Help/variable/CMAKE_LANG_FLAGS_RELWITHDEBINFO.rst b/Help/variable/CMAKE_LANG_FLAGS_RELWITHDEBINFO.rst
index 16bd4e9..962768e 100644
--- a/Help/variable/CMAKE_LANG_FLAGS_RELWITHDEBINFO.rst
+++ b/Help/variable/CMAKE_LANG_FLAGS_RELWITHDEBINFO.rst
@@ -1,7 +1,7 @@
CMAKE_<LANG>_FLAGS_RELWITHDEBINFO
---------------------------------
-Flags for RelWithDebInfo type or configuration.
+Flags for ``RelWithDebInfo`` type or configuration.
-<LANG> flags used when CMAKE_BUILD_TYPE is RelWithDebInfo. Short for
-Release With Debug Information.
+``<LANG>`` flags used when :variable:`CMAKE_BUILD_TYPE` is ``RelWithDebInfo``
+(short for Release With Debug Information).
diff --git a/Help/variable/CMAKE_LANG_GHS_KERNEL_FLAGS_DEBUG.rst b/Help/variable/CMAKE_LANG_GHS_KERNEL_FLAGS_DEBUG.rst
index c5915c3..1f639a3 100644
--- a/Help/variable/CMAKE_LANG_GHS_KERNEL_FLAGS_DEBUG.rst
+++ b/Help/variable/CMAKE_LANG_GHS_KERNEL_FLAGS_DEBUG.rst
@@ -1,6 +1,6 @@
CMAKE_<LANG>_GHS_KERNEL_FLAGS_DEBUG
-----------------------------------
-GHS kernel flags for Debug build type or configuration.
+GHS kernel flags for ``Debug`` build type or configuration.
-<LANG> flags used when CMAKE_BUILD_TYPE is Debug.
+``<LANG>`` flags used when :variable:`CMAKE_BUILD_TYPE` is ``Debug``.
diff --git a/Help/variable/CMAKE_LANG_GHS_KERNEL_FLAGS_MINSIZEREL.rst b/Help/variable/CMAKE_LANG_GHS_KERNEL_FLAGS_MINSIZEREL.rst
index f80e785..94e2115 100644
--- a/Help/variable/CMAKE_LANG_GHS_KERNEL_FLAGS_MINSIZEREL.rst
+++ b/Help/variable/CMAKE_LANG_GHS_KERNEL_FLAGS_MINSIZEREL.rst
@@ -1,7 +1,7 @@
CMAKE_<LANG>_GHS_KERNEL_FLAGS_MINSIZEREL
----------------------------------------
-GHS kernel flags for MinSizeRel build type or configuration.
+GHS kernel flags for ``MinSizeRel`` build type or configuration.
-<LANG> flags used when CMAKE_BUILD_TYPE is MinSizeRel.Short for
-minimum size release.
+``<LANG>`` flags used when :variable:`CMAKE_BUILD_TYPE` is ``MinSizeRel``
+(short for minimum size release).
diff --git a/Help/variable/CMAKE_LANG_GHS_KERNEL_FLAGS_RELEASE.rst b/Help/variable/CMAKE_LANG_GHS_KERNEL_FLAGS_RELEASE.rst
index fe02bc3..74566ef 100644
--- a/Help/variable/CMAKE_LANG_GHS_KERNEL_FLAGS_RELEASE.rst
+++ b/Help/variable/CMAKE_LANG_GHS_KERNEL_FLAGS_RELEASE.rst
@@ -1,6 +1,6 @@
CMAKE_<LANG>_GHS_KERNEL_FLAGS_RELEASE
-------------------------------------
-GHS kernel flags for Release build type or configuration.
+GHS kernel flags for ``Release`` build type or configuration.
-<LANG> flags used when CMAKE_BUILD_TYPE is Release
+``<LANG>`` flags used when :variable:`CMAKE_BUILD_TYPE` is ``Release``.
diff --git a/Help/variable/CMAKE_LANG_GHS_KERNEL_FLAGS_RELWITHDEBINFO.rst b/Help/variable/CMAKE_LANG_GHS_KERNEL_FLAGS_RELWITHDEBINFO.rst
index 220f7f9..d148193 100644
--- a/Help/variable/CMAKE_LANG_GHS_KERNEL_FLAGS_RELWITHDEBINFO.rst
+++ b/Help/variable/CMAKE_LANG_GHS_KERNEL_FLAGS_RELWITHDEBINFO.rst
@@ -1,7 +1,7 @@
CMAKE_<LANG>_GHS_KERNEL_FLAGS_RELWITHDEBINFO
--------------------------------------------
-GHS kernel flags for RelWithDebInfo type or configuration.
+GHS kernel flags for ``RelWithDebInfo`` type or configuration.
-<LANG> flags used when CMAKE_BUILD_TYPE is RelWithDebInfo. Short for
-Release With Debug Information.
+``<LANG>`` flags used when :variable:`CMAKE_BUILD_TYPE` is ``RelWithDebInfo``
+(short for Release With Debug Information).
diff --git a/Help/variable/CMAKE_LANG_IMPLICIT_INCLUDE_DIRECTORIES.rst b/Help/variable/CMAKE_LANG_IMPLICIT_INCLUDE_DIRECTORIES.rst
index c60e18c..cc80851 100644
--- a/Help/variable/CMAKE_LANG_IMPLICIT_INCLUDE_DIRECTORIES.rst
+++ b/Help/variable/CMAKE_LANG_IMPLICIT_INCLUDE_DIRECTORIES.rst
@@ -4,6 +4,6 @@ CMAKE_<LANG>_IMPLICIT_INCLUDE_DIRECTORIES
Directories implicitly searched by the compiler for header files.
CMake does not explicitly specify these directories on compiler
-command lines for language <LANG>. This prevents system include
+command lines for language ``<LANG>``. This prevents system include
directories from being treated as user include directories on some
compilers.
diff --git a/Help/variable/CMAKE_LANG_IMPLICIT_LINK_DIRECTORIES.rst b/Help/variable/CMAKE_LANG_IMPLICIT_LINK_DIRECTORIES.rst
index 568950c..a0bd830 100644
--- a/Help/variable/CMAKE_LANG_IMPLICIT_LINK_DIRECTORIES.rst
+++ b/Help/variable/CMAKE_LANG_IMPLICIT_LINK_DIRECTORIES.rst
@@ -1,7 +1,7 @@
CMAKE_<LANG>_IMPLICIT_LINK_DIRECTORIES
--------------------------------------
-Implicit linker search path detected for language <LANG>.
+Implicit linker search path detected for language ``<LANG>``.
Compilers typically pass directories containing language runtime
libraries and default library search paths when they invoke a linker.
@@ -10,8 +10,8 @@ language. CMake automatically detects these directories for each
language and reports the results in this variable.
When a library in one of these directories is given by full path to
-target_link_libraries() CMake will generate the -l<name> form on link
-lines to ensure the linker searches its implicit directories for the
+:command:`target_link_libraries` CMake will generate the ``-l<name>`` form on
+link lines to ensure the linker searches its implicit directories for the
library. Note that some toolchains read implicit directories from an
-environment variable such as LIBRARY_PATH so keep its value consistent
+environment variable such as ``LIBRARY_PATH`` so keep its value consistent
when operating in a given build tree.
diff --git a/Help/variable/CMAKE_LANG_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES.rst b/Help/variable/CMAKE_LANG_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES.rst
index 05e6ddb..61ccc5a 100644
--- a/Help/variable/CMAKE_LANG_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES.rst
+++ b/Help/variable/CMAKE_LANG_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES.rst
@@ -1,7 +1,7 @@
CMAKE_<LANG>_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES
------------------------------------------------
-Implicit linker framework search path detected for language <LANG>.
+Implicit linker framework search path detected for language ``<LANG>``.
These paths are implicit linker framework search directories for the
compiler's language. CMake automatically detects these directories
diff --git a/Help/variable/CMAKE_LANG_IMPLICIT_LINK_LIBRARIES.rst b/Help/variable/CMAKE_LANG_IMPLICIT_LINK_LIBRARIES.rst
index fddfed8..ec16477 100644
--- a/Help/variable/CMAKE_LANG_IMPLICIT_LINK_LIBRARIES.rst
+++ b/Help/variable/CMAKE_LANG_IMPLICIT_LINK_LIBRARIES.rst
@@ -1,7 +1,7 @@
CMAKE_<LANG>_IMPLICIT_LINK_LIBRARIES
------------------------------------
-Implicit link libraries and flags detected for language <LANG>.
+Implicit link libraries and flags detected for language ``<LANG>``.
Compilers typically pass language runtime library names and other
flags when they invoke a linker. These flags are implicit link
diff --git a/Help/variable/CMAKE_LANG_LIBRARY_ARCHITECTURE.rst b/Help/variable/CMAKE_LANG_LIBRARY_ARCHITECTURE.rst
index 4f31494..7f888ee 100644
--- a/Help/variable/CMAKE_LANG_LIBRARY_ARCHITECTURE.rst
+++ b/Help/variable/CMAKE_LANG_LIBRARY_ARCHITECTURE.rst
@@ -1,8 +1,8 @@
CMAKE_<LANG>_LIBRARY_ARCHITECTURE
---------------------------------
-Target architecture library directory name detected for <lang>.
+Target architecture library directory name detected for ``<LANG>``.
-If the <lang> compiler passes to the linker an architecture-specific
-system library search directory such as <prefix>/lib/<arch> this
-variable contains the <arch> name if/as detected by CMake.
+If the ``<LANG>`` compiler passes to the linker an architecture-specific
+system library search directory such as ``<prefix>/lib/<arch>`` this
+variable contains the ``<arch>`` name if/as detected by CMake.
diff --git a/Help/variable/CMAKE_LANG_LINKER_PREFERENCE.rst b/Help/variable/CMAKE_LANG_LINKER_PREFERENCE.rst
index af7ee60..ff82f8b 100644
--- a/Help/variable/CMAKE_LANG_LINKER_PREFERENCE.rst
+++ b/Help/variable/CMAKE_LANG_LINKER_PREFERENCE.rst
@@ -5,7 +5,7 @@ Preference value for linker language selection.
The "linker language" for executable, shared library, and module
targets is the language whose compiler will invoke the linker. The
-LINKER_LANGUAGE target property sets the language explicitly.
+:prop_tgt:`LINKER_LANGUAGE` target property sets the language explicitly.
Otherwise, the linker language is that whose linker preference value
is highest among languages compiled and linked into the target. See
-also the CMAKE_<LANG>_LINKER_PREFERENCE_PROPAGATES variable.
+also the :variable:`CMAKE_<LANG>_LINKER_PREFERENCE_PROPAGATES` variable.
diff --git a/Help/variable/CMAKE_LANG_LINKER_PREFERENCE_PROPAGATES.rst b/Help/variable/CMAKE_LANG_LINKER_PREFERENCE_PROPAGATES.rst
index d513767..dbbeb0a 100644
--- a/Help/variable/CMAKE_LANG_LINKER_PREFERENCE_PROPAGATES.rst
+++ b/Help/variable/CMAKE_LANG_LINKER_PREFERENCE_PROPAGATES.rst
@@ -1,7 +1,7 @@
CMAKE_<LANG>_LINKER_PREFERENCE_PROPAGATES
-----------------------------------------
-True if CMAKE_<LANG>_LINKER_PREFERENCE propagates across targets.
+True if :variable:`CMAKE_<LANG>_LINKER_PREFERENCE` propagates across targets.
This is used when CMake selects a linker language for a target.
Languages compiled directly into the target are always considered. A
diff --git a/Help/variable/CMAKE_LANG_OUTPUT_EXTENSION.rst b/Help/variable/CMAKE_LANG_OUTPUT_EXTENSION.rst
index 22fac29..0fbc566 100644
--- a/Help/variable/CMAKE_LANG_OUTPUT_EXTENSION.rst
+++ b/Help/variable/CMAKE_LANG_OUTPUT_EXTENSION.rst
@@ -3,5 +3,5 @@ CMAKE_<LANG>_OUTPUT_EXTENSION
Extension for the output of a compile for a single file.
-This is the extension for an object file for the given <LANG>. For
-example .obj for C on Windows.
+This is the extension for an object file for the given ``<LANG>``. For
+example ``.obj`` for C on Windows.
diff --git a/Help/variable/CMAKE_LANG_SIMULATE_ID.rst b/Help/variable/CMAKE_LANG_SIMULATE_ID.rst
index 646c0db..15c87a1 100644
--- a/Help/variable/CMAKE_LANG_SIMULATE_ID.rst
+++ b/Help/variable/CMAKE_LANG_SIMULATE_ID.rst
@@ -5,5 +5,5 @@ Identification string of "simulated" compiler.
Some compilers simulate other compilers to serve as drop-in
replacements. When CMake detects such a compiler it sets this
-variable to what would have been the CMAKE_<LANG>_COMPILER_ID for the
-simulated compiler.
+variable to what would have been the :variable:`CMAKE_<LANG>_COMPILER_ID` for
+the simulated compiler.
diff --git a/Help/variable/CMAKE_LANG_SIMULATE_VERSION.rst b/Help/variable/CMAKE_LANG_SIMULATE_VERSION.rst
index 982053d..d6325e0 100644
--- a/Help/variable/CMAKE_LANG_SIMULATE_VERSION.rst
+++ b/Help/variable/CMAKE_LANG_SIMULATE_VERSION.rst
@@ -5,5 +5,5 @@ Version string of "simulated" compiler.
Some compilers simulate other compilers to serve as drop-in
replacements. When CMake detects such a compiler it sets this
-variable to what would have been the CMAKE_<LANG>_COMPILER_VERSION for
-the simulated compiler.
+variable to what would have been the :variable:`CMAKE_<LANG>_COMPILER_VERSION`
+for the simulated compiler.
diff --git a/Help/variable/CMAKE_LANG_SIZEOF_DATA_PTR.rst b/Help/variable/CMAKE_LANG_SIZEOF_DATA_PTR.rst
index c85b5e0..7465923 100644
--- a/Help/variable/CMAKE_LANG_SIZEOF_DATA_PTR.rst
+++ b/Help/variable/CMAKE_LANG_SIZEOF_DATA_PTR.rst
@@ -1,7 +1,7 @@
CMAKE_<LANG>_SIZEOF_DATA_PTR
----------------------------
-Size of pointer-to-data types for language <LANG>.
+Size of pointer-to-data types for language ``<LANG>``.
This holds the size (in bytes) of pointer-to-data types in the target
-platform ABI. It is defined for languages C and CXX (C++).
+platform ABI. It is defined for languages ``C`` and ``CXX`` (C++).
diff --git a/Help/variable/CMAKE_LIBRARY_ARCHITECTURE.rst b/Help/variable/CMAKE_LIBRARY_ARCHITECTURE.rst
index c9a15f3..8a7dcbd 100644
--- a/Help/variable/CMAKE_LIBRARY_ARCHITECTURE.rst
+++ b/Help/variable/CMAKE_LIBRARY_ARCHITECTURE.rst
@@ -3,5 +3,5 @@ CMAKE_LIBRARY_ARCHITECTURE
Target architecture library directory name, if detected.
-This is the value of CMAKE_<lang>_LIBRARY_ARCHITECTURE as detected for
-one of the enabled languages.
+This is the value of :variable:`CMAKE_<LANG>_LIBRARY_ARCHITECTURE` as detected
+for one of the enabled languages.
diff --git a/Help/variable/CMAKE_LIBRARY_ARCHITECTURE_REGEX.rst b/Help/variable/CMAKE_LIBRARY_ARCHITECTURE_REGEX.rst
index 6c41269..1eb2ac2 100644
--- a/Help/variable/CMAKE_LIBRARY_ARCHITECTURE_REGEX.rst
+++ b/Help/variable/CMAKE_LIBRARY_ARCHITECTURE_REGEX.rst
@@ -3,5 +3,5 @@ CMAKE_LIBRARY_ARCHITECTURE_REGEX
Regex matching possible target architecture library directory names.
-This is used to detect CMAKE_<lang>_LIBRARY_ARCHITECTURE from the
-implicit linker search path by matching the <arch> name.
+This is used to detect :variable:`CMAKE_<LANG>_LIBRARY_ARCHITECTURE` from the
+implicit linker search path by matching the ``<arch>`` name.
diff --git a/Help/variable/CMAKE_LIBRARY_PATH_FLAG.rst b/Help/variable/CMAKE_LIBRARY_PATH_FLAG.rst
index ede39e9..ebe5fda 100644
--- a/Help/variable/CMAKE_LIBRARY_PATH_FLAG.rst
+++ b/Help/variable/CMAKE_LIBRARY_PATH_FLAG.rst
@@ -4,4 +4,4 @@ CMAKE_LIBRARY_PATH_FLAG
The flag to be used to add a library search path to a compiler.
The flag will be used to specify a library directory to the compiler.
-On most compilers this is "-L".
+On most compilers this is ``-L``.
diff --git a/Help/variable/CMAKE_LINK_DEF_FILE_FLAG.rst b/Help/variable/CMAKE_LINK_DEF_FILE_FLAG.rst
index 382447c..fa09f9f 100644
--- a/Help/variable/CMAKE_LINK_DEF_FILE_FLAG.rst
+++ b/Help/variable/CMAKE_LINK_DEF_FILE_FLAG.rst
@@ -1,7 +1,7 @@
CMAKE_LINK_DEF_FILE_FLAG
------------------------
-Linker flag to be used to specify a .def file for dll creation.
+Linker flag to be used to specify a ``.def`` file for dll creation.
-The flag will be used to add a .def file when creating a dll on
+The flag will be used to add a ``.def`` file when creating a dll on
Windows; this is only defined on Windows.
diff --git a/Help/variable/CMAKE_LINK_DEPENDS_NO_SHARED.rst b/Help/variable/CMAKE_LINK_DEPENDS_NO_SHARED.rst
index 6ae7df6..cec7906 100644
--- a/Help/variable/CMAKE_LINK_DEPENDS_NO_SHARED.rst
+++ b/Help/variable/CMAKE_LINK_DEPENDS_NO_SHARED.rst
@@ -3,6 +3,6 @@ CMAKE_LINK_DEPENDS_NO_SHARED
Whether to skip link dependencies on shared library files.
-This variable initializes the LINK_DEPENDS_NO_SHARED property on
+This variable initializes the :prop_tgt:`LINK_DEPENDS_NO_SHARED` property on
targets when they are created. See that target property for
additional information.
diff --git a/Help/variable/CMAKE_LINK_INTERFACE_LIBRARIES.rst b/Help/variable/CMAKE_LINK_INTERFACE_LIBRARIES.rst
index efe6fd7..33865da 100644
--- a/Help/variable/CMAKE_LINK_INTERFACE_LIBRARIES.rst
+++ b/Help/variable/CMAKE_LINK_INTERFACE_LIBRARIES.rst
@@ -1,8 +1,8 @@
CMAKE_LINK_INTERFACE_LIBRARIES
------------------------------
-Default value for LINK_INTERFACE_LIBRARIES of targets.
+Default value for :prop_tgt:`LINK_INTERFACE_LIBRARIES` of targets.
-This variable is used to initialize the LINK_INTERFACE_LIBRARIES
+This variable is used to initialize the :prop_tgt:`LINK_INTERFACE_LIBRARIES`
property on all the targets. See that target property for additional
information.
diff --git a/Help/variable/CMAKE_LINK_LIBRARY_FLAG.rst b/Help/variable/CMAKE_LINK_LIBRARY_FLAG.rst
index c3e02d7..b5197e4 100644
--- a/Help/variable/CMAKE_LINK_LIBRARY_FLAG.rst
+++ b/Help/variable/CMAKE_LINK_LIBRARY_FLAG.rst
@@ -4,4 +4,4 @@ CMAKE_LINK_LIBRARY_FLAG
Flag to be used to link a library into an executable.
The flag will be used to specify a library to link to an executable.
-On most compilers this is "-l".
+On most compilers this is ``-l``.
diff --git a/Help/variable/CMAKE_LINK_LIBRARY_SUFFIX.rst b/Help/variable/CMAKE_LINK_LIBRARY_SUFFIX.rst
index 390298d..0ddafe8 100644
--- a/Help/variable/CMAKE_LINK_LIBRARY_SUFFIX.rst
+++ b/Help/variable/CMAKE_LINK_LIBRARY_SUFFIX.rst
@@ -3,4 +3,4 @@ CMAKE_LINK_LIBRARY_SUFFIX
The suffix for libraries that you link to.
-The suffix to use for the end of a library filename, .lib on Windows.
+The suffix to use for the end of a library filename, ``.lib`` on Windows.
diff --git a/Help/variable/CMAKE_LINK_SEARCH_END_STATIC.rst b/Help/variable/CMAKE_LINK_SEARCH_END_STATIC.rst
new file mode 100644
index 0000000..54cdaaa
--- /dev/null
+++ b/Help/variable/CMAKE_LINK_SEARCH_END_STATIC.rst
@@ -0,0 +1,19 @@
+CMAKE_LINK_SEARCH_END_STATIC
+----------------------------
+
+End a link line such that static system libraries are used.
+
+Some linkers support switches such as ``-Bstatic`` and ``-Bdynamic`` to
+determine whether to use static or shared libraries for ``-lXXX`` options.
+CMake uses these options to set the link type for libraries whose full
+paths are not known or (in some cases) are in implicit link
+directories for the platform. By default CMake adds an option at the
+end of the library list (if necessary) to set the linker search type
+back to its starting type. This property switches the final linker
+search type to ``-Bstatic`` regardless of how it started.
+
+This variable is used to initialize the target property
+:prop_tgt:`LINK_SEARCH_END_STATIC` for all targets. If set, it's
+value is also used by the :command:`try_compile` command.
+
+See also :variable:`CMAKE_LINK_SEARCH_START_STATIC`.
diff --git a/Help/variable/CMAKE_LINK_SEARCH_START_STATIC.rst b/Help/variable/CMAKE_LINK_SEARCH_START_STATIC.rst
new file mode 100644
index 0000000..0d52a31
--- /dev/null
+++ b/Help/variable/CMAKE_LINK_SEARCH_START_STATIC.rst
@@ -0,0 +1,20 @@
+CMAKE_LINK_SEARCH_START_STATIC
+------------------------------
+
+Assume the linker looks for static libraries by default.
+
+Some linkers support switches such as ``-Bstatic`` and ``-Bdynamic`` to
+determine whether to use static or shared libraries for ``-lXXX`` options.
+CMake uses these options to set the link type for libraries whose full
+paths are not known or (in some cases) are in implicit link
+directories for the platform. By default the linker search type is
+assumed to be ``-Bdynamic`` at the beginning of the library list. This
+property switches the assumption to ``-Bstatic``. It is intended for use
+when linking an executable statically (e.g. with the GNU ``-static``
+option).
+
+This variable is used to initialize the target property
+:prop_tgt:`LINK_SEARCH_START_STATIC` for all targets. If set, it's
+value is also used by the :command:`try_compile` command.
+
+See also :variable:`CMAKE_LINK_SEARCH_END_STATIC`.
diff --git a/Help/variable/CMAKE_MACOSX_BUNDLE.rst b/Help/variable/CMAKE_MACOSX_BUNDLE.rst
index e4768f3..0badaf0 100644
--- a/Help/variable/CMAKE_MACOSX_BUNDLE.rst
+++ b/Help/variable/CMAKE_MACOSX_BUNDLE.rst
@@ -1,7 +1,7 @@
CMAKE_MACOSX_BUNDLE
-------------------
-Default value for MACOSX_BUNDLE of targets.
+Default value for :prop_tgt:`MACOSX_BUNDLE` of targets.
-This variable is used to initialize the MACOSX_BUNDLE property on all
-the targets. See that target property for additional information.
+This variable is used to initialize the :prop_tgt:`MACOSX_BUNDLE` property on
+all the targets. See that target property for additional information.
diff --git a/Help/variable/CMAKE_MAKE_PROGRAM.rst b/Help/variable/CMAKE_MAKE_PROGRAM.rst
index 85b098b..edf2732 100644
--- a/Help/variable/CMAKE_MAKE_PROGRAM.rst
+++ b/Help/variable/CMAKE_MAKE_PROGRAM.rst
@@ -8,18 +8,18 @@ name if it is expected to be in the ``PATH``.
The tool selected depends on the :variable:`CMAKE_GENERATOR` used
to configure the project:
-* The Makefile generators set this to ``make``, ``gmake``, or
- a generator-specific tool (e.g. ``nmake`` for "NMake Makefiles").
+* The :ref:`Makefile Generators` set this to ``make``, ``gmake``, or
+ a generator-specific tool (e.g. ``nmake`` for :generator:`NMake Makefiles`).
These generators store ``CMAKE_MAKE_PROGRAM`` in the CMake cache
so that it may be edited by the user.
-* The Ninja generator sets this to ``ninja``.
+* The :generator:`Ninja` generator sets this to ``ninja``.
This generator stores ``CMAKE_MAKE_PROGRAM`` in the CMake cache
so that it may be edited by the user.
-* The Xcode generator sets this to ``xcodebuild`` (or possibly an
+* The :generator:`Xcode` generator sets this to ``xcodebuild`` (or possibly an
otherwise undocumented ``cmakexbuild`` wrapper implementing some
workarounds).
@@ -33,7 +33,7 @@ to configure the project:
a user or project explicitly adds ``CMAKE_MAKE_PROGRAM`` to
the CMake cache then CMake will use the specified value.
-* The Visual Studio generators set this to the full path to
+* The :ref:`Visual Studio Generators` set this to the full path to
``MSBuild.exe`` (VS >= 10), ``devenv.com`` (VS 7,8,9),
``VCExpress.exe`` (VS Express 8,9), or ``msdev.exe`` (VS 6).
(See also variables
diff --git a/Help/variable/CMAKE_MAP_IMPORTED_CONFIG_CONFIG.rst b/Help/variable/CMAKE_MAP_IMPORTED_CONFIG_CONFIG.rst
index 41ccde1..ed29afe 100644
--- a/Help/variable/CMAKE_MAP_IMPORTED_CONFIG_CONFIG.rst
+++ b/Help/variable/CMAKE_MAP_IMPORTED_CONFIG_CONFIG.rst
@@ -1,8 +1,8 @@
CMAKE_MAP_IMPORTED_CONFIG_<CONFIG>
----------------------------------
-Default value for MAP_IMPORTED_CONFIG_<CONFIG> of targets.
+Default value for :prop_tgt:`MAP_IMPORTED_CONFIG_<CONFIG>` of targets.
-This variable is used to initialize the MAP_IMPORTED_CONFIG_<CONFIG>
-property on all the targets. See that target property for additional
-information.
+This variable is used to initialize the
+:prop_tgt:`MAP_IMPORTED_CONFIG_<CONFIG>` property on all the targets. See
+that target property for additional information.
diff --git a/Help/variable/CMAKE_MFC_FLAG.rst b/Help/variable/CMAKE_MFC_FLAG.rst
index 221d26e..f60e7a5 100644
--- a/Help/variable/CMAKE_MFC_FLAG.rst
+++ b/Help/variable/CMAKE_MFC_FLAG.rst
@@ -3,10 +3,10 @@ CMAKE_MFC_FLAG
Tell cmake to use MFC for an executable or dll.
-This can be set in a CMakeLists.txt file and will enable MFC in the
-application. It should be set to 1 for the static MFC library, and 2
+This can be set in a ``CMakeLists.txt`` file and will enable MFC in the
+application. It should be set to ``1`` for the static MFC library, and ``2``
for the shared MFC library. This is used in Visual Studio 6 and 7
-project files. The CMakeSetup dialog used MFC and the CMakeLists.txt
+project files. The CMakeSetup dialog used MFC and the ``CMakeLists.txt``
looks like this:
::
diff --git a/Help/variable/CMAKE_MINIMUM_REQUIRED_VERSION.rst b/Help/variable/CMAKE_MINIMUM_REQUIRED_VERSION.rst
index 351de44..5a51634 100644
--- a/Help/variable/CMAKE_MINIMUM_REQUIRED_VERSION.rst
+++ b/Help/variable/CMAKE_MINIMUM_REQUIRED_VERSION.rst
@@ -1,7 +1,7 @@
CMAKE_MINIMUM_REQUIRED_VERSION
------------------------------
-Version specified to cmake_minimum_required command
+Version specified to :command:`cmake_minimum_required` command
-Variable containing the VERSION component specified in the
-cmake_minimum_required command.
+Variable containing the ``VERSION`` component specified in the
+:command:`cmake_minimum_required` command.
diff --git a/Help/variable/CMAKE_MODULE_LINKER_FLAGS_CONFIG.rst b/Help/variable/CMAKE_MODULE_LINKER_FLAGS_CONFIG.rst
index 87a1901..393263e 100644
--- a/Help/variable/CMAKE_MODULE_LINKER_FLAGS_CONFIG.rst
+++ b/Help/variable/CMAKE_MODULE_LINKER_FLAGS_CONFIG.rst
@@ -3,4 +3,4 @@ CMAKE_MODULE_LINKER_FLAGS_<CONFIG>
Flags to be used when linking a module.
-Same as CMAKE_C_FLAGS_* but used by the linker when creating modules.
+Same as ``CMAKE_C_FLAGS_*`` but used by the linker when creating modules.
diff --git a/Help/variable/CMAKE_NOT_USING_CONFIG_FLAGS.rst b/Help/variable/CMAKE_NOT_USING_CONFIG_FLAGS.rst
index cbe0350..98960c5 100644
--- a/Help/variable/CMAKE_NOT_USING_CONFIG_FLAGS.rst
+++ b/Help/variable/CMAKE_NOT_USING_CONFIG_FLAGS.rst
@@ -1,7 +1,7 @@
CMAKE_NOT_USING_CONFIG_FLAGS
----------------------------
-Skip _BUILD_TYPE flags if true.
+Skip ``_BUILD_TYPE`` flags if true.
This is an internal flag used by the generators in CMake to tell CMake
-to skip the _BUILD_TYPE flags.
+to skip the ``_BUILD_TYPE`` flags.
diff --git a/Help/variable/CMAKE_NO_SYSTEM_FROM_IMPORTED.rst b/Help/variable/CMAKE_NO_SYSTEM_FROM_IMPORTED.rst
index c1919af..61e04b4 100644
--- a/Help/variable/CMAKE_NO_SYSTEM_FROM_IMPORTED.rst
+++ b/Help/variable/CMAKE_NO_SYSTEM_FROM_IMPORTED.rst
@@ -1,8 +1,8 @@
CMAKE_NO_SYSTEM_FROM_IMPORTED
-----------------------------
-Default value for NO_SYSTEM_FROM_IMPORTED of targets.
+Default value for :prop_tgt:`NO_SYSTEM_FROM_IMPORTED` of targets.
-This variable is used to initialize the NO_SYSTEM_FROM_IMPORTED
+This variable is used to initialize the :prop_tgt:`NO_SYSTEM_FROM_IMPORTED`
property on all the targets. See that target property for additional
information.
diff --git a/Help/variable/CMAKE_PARENT_LIST_FILE.rst b/Help/variable/CMAKE_PARENT_LIST_FILE.rst
index 5566a72..cfd8608 100644
--- a/Help/variable/CMAKE_PARENT_LIST_FILE.rst
+++ b/Help/variable/CMAKE_PARENT_LIST_FILE.rst
@@ -3,7 +3,7 @@ CMAKE_PARENT_LIST_FILE
Full path to the CMake file that included the current one.
-While processing a CMake file loaded by include() or find_package()
-this variable contains the full path to the file including it. The
-top of the include stack is always the CMakeLists.txt for the current
-directory. See also CMAKE_CURRENT_LIST_FILE.
+While processing a CMake file loaded by :command:`include` or
+:command:`find_package` this variable contains the full path to the file
+including it. The top of the include stack is always the ``CMakeLists.txt``
+for the current directory. See also :variable:`CMAKE_CURRENT_LIST_FILE`.
diff --git a/Help/variable/CMAKE_POLICY_DEFAULT_CMPNNNN.rst b/Help/variable/CMAKE_POLICY_DEFAULT_CMPNNNN.rst
index e401aa5..43582be 100644
--- a/Help/variable/CMAKE_POLICY_DEFAULT_CMPNNNN.rst
+++ b/Help/variable/CMAKE_POLICY_DEFAULT_CMPNNNN.rst
@@ -1,16 +1,17 @@
CMAKE_POLICY_DEFAULT_CMP<NNNN>
------------------------------
-Default for CMake Policy CMP<NNNN> when it is otherwise left unset.
+Default for CMake Policy ``CMP<NNNN>`` when it is otherwise left unset.
-Commands cmake_minimum_required(VERSION) and cmake_policy(VERSION) by
-default leave policies introduced after the given version unset. Set
-CMAKE_POLICY_DEFAULT_CMP<NNNN> to OLD or NEW to specify the default
-for policy CMP<NNNN>, where <NNNN> is the policy number.
+Commands :command:`cmake_minimum_required(VERSION)` and
+:command:`cmake_policy(VERSION)` by default leave policies introduced after
+the given version unset. Set ``CMAKE_POLICY_DEFAULT_CMP<NNNN>`` to ``OLD``
+or ``NEW`` to specify the default for policy ``CMP<NNNN>``, where ``<NNNN>``
+is the policy number.
This variable should not be set by a project in CMake code; use
-cmake_policy(SET) instead. Users running CMake may set this variable
-in the cache (e.g. -DCMAKE_POLICY_DEFAULT_CMP<NNNN>=<OLD|NEW>) to set
-a policy not otherwise set by the project. Set to OLD to quiet a
-policy warning while using old behavior or to NEW to try building the
+:command:`cmake_policy(SET)` instead. Users running CMake may set this
+variable in the cache (e.g. ``-DCMAKE_POLICY_DEFAULT_CMP<NNNN>=<OLD|NEW>``)
+to set a policy not otherwise set by the project. Set to ``OLD`` to quiet a
+policy warning while using old behavior or to ``NEW`` to try building the
project with new behavior.
diff --git a/Help/variable/CMAKE_POSITION_INDEPENDENT_CODE.rst b/Help/variable/CMAKE_POSITION_INDEPENDENT_CODE.rst
index 5e71665..43b1397 100644
--- a/Help/variable/CMAKE_POSITION_INDEPENDENT_CODE.rst
+++ b/Help/variable/CMAKE_POSITION_INDEPENDENT_CODE.rst
@@ -1,8 +1,9 @@
CMAKE_POSITION_INDEPENDENT_CODE
-------------------------------
-Default value for POSITION_INDEPENDENT_CODE of targets.
+Default value for :prop_tgt:`POSITION_INDEPENDENT_CODE` of targets.
-This variable is used to initialize the POSITION_INDEPENDENT_CODE
-property on all the targets. See that target property for additional
-information.
+This variable is used to initialize the
+:prop_tgt:`POSITION_INDEPENDENT_CODE` property on all the targets.
+See that target property for additional information. If set, it's
+value is also used by the :command:`try_compile` command.
diff --git a/Help/variable/CMAKE_PROJECT_NAME.rst b/Help/variable/CMAKE_PROJECT_NAME.rst
index 4734705..431e9f3 100644
--- a/Help/variable/CMAKE_PROJECT_NAME.rst
+++ b/Help/variable/CMAKE_PROJECT_NAME.rst
@@ -4,4 +4,4 @@ CMAKE_PROJECT_NAME
The name of the current project.
This specifies name of the current project from the closest inherited
-PROJECT command.
+:command:`project` command.
diff --git a/Help/variable/CMAKE_ROOT.rst b/Help/variable/CMAKE_ROOT.rst
index f963a7f..1d0a8af 100644
--- a/Help/variable/CMAKE_ROOT.rst
+++ b/Help/variable/CMAKE_ROOT.rst
@@ -3,6 +3,6 @@ CMAKE_ROOT
Install directory for running cmake.
-This is the install root for the running CMake and the Modules
+This is the install root for the running CMake and the ``Modules``
directory can be found here. This is commonly used in this format:
-${CMAKE_ROOT}/Modules
+``${CMAKE_ROOT}/Modules``
diff --git a/Help/variable/CMAKE_SCRIPT_MODE_FILE.rst b/Help/variable/CMAKE_SCRIPT_MODE_FILE.rst
index ad73cc0..981af60 100644
--- a/Help/variable/CMAKE_SCRIPT_MODE_FILE.rst
+++ b/Help/variable/CMAKE_SCRIPT_MODE_FILE.rst
@@ -1,8 +1,9 @@
CMAKE_SCRIPT_MODE_FILE
----------------------
-Full path to the -P script file currently being processed.
+Full path to the :manual:`cmake(1)` ``-P`` script file currently being
+processed.
-When run in -P script mode, CMake sets this variable to the full path
-of the script file. When run to configure a CMakeLists.txt file, this
-variable is not set.
+When run in :manual:`cmake(1)` ``-P`` script mode, CMake sets this variable to
+the full path of the script file. When run to configure a ``CMakeLists.txt``
+file, this variable is not set.
diff --git a/Help/variable/CMAKE_SHARED_LIBRARY_PREFIX.rst b/Help/variable/CMAKE_SHARED_LIBRARY_PREFIX.rst
index a863e2a..8afabaf 100644
--- a/Help/variable/CMAKE_SHARED_LIBRARY_PREFIX.rst
+++ b/Help/variable/CMAKE_SHARED_LIBRARY_PREFIX.rst
@@ -3,6 +3,6 @@ CMAKE_SHARED_LIBRARY_PREFIX
The prefix for shared libraries that you link to.
-The prefix to use for the name of a shared library, lib on UNIX.
+The prefix to use for the name of a shared library, ``lib`` on UNIX.
-CMAKE_SHARED_LIBRARY_PREFIX_<LANG> overrides this for language <LANG>.
+``CMAKE_SHARED_LIBRARY_PREFIX_<LANG>`` overrides this for language ``<LANG>``.
diff --git a/Help/variable/CMAKE_SHARED_LIBRARY_SUFFIX.rst b/Help/variable/CMAKE_SHARED_LIBRARY_SUFFIX.rst
index c296ecd..1f96a32 100644
--- a/Help/variable/CMAKE_SHARED_LIBRARY_SUFFIX.rst
+++ b/Help/variable/CMAKE_SHARED_LIBRARY_SUFFIX.rst
@@ -3,7 +3,7 @@ CMAKE_SHARED_LIBRARY_SUFFIX
The suffix for shared libraries that you link to.
-The suffix to use for the end of a shared library filename, .dll on
+The suffix to use for the end of a shared library filename, ``.dll`` on
Windows.
-CMAKE_SHARED_LIBRARY_SUFFIX_<LANG> overrides this for language <LANG>.
+``CMAKE_SHARED_LIBRARY_SUFFIX_<LANG>`` overrides this for language ``<LANG>``.
diff --git a/Help/variable/CMAKE_SHARED_LINKER_FLAGS_CONFIG.rst b/Help/variable/CMAKE_SHARED_LINKER_FLAGS_CONFIG.rst
index fedc626..4bf87a0 100644
--- a/Help/variable/CMAKE_SHARED_LINKER_FLAGS_CONFIG.rst
+++ b/Help/variable/CMAKE_SHARED_LINKER_FLAGS_CONFIG.rst
@@ -3,5 +3,5 @@ CMAKE_SHARED_LINKER_FLAGS_<CONFIG>
Flags to be used when linking a shared library.
-Same as CMAKE_C_FLAGS_* but used by the linker when creating shared
+Same as ``CMAKE_C_FLAGS_*`` but used by the linker when creating shared
libraries.
diff --git a/Help/variable/CMAKE_SHARED_MODULE_PREFIX.rst b/Help/variable/CMAKE_SHARED_MODULE_PREFIX.rst
index a5a2428..d6eef98 100644
--- a/Help/variable/CMAKE_SHARED_MODULE_PREFIX.rst
+++ b/Help/variable/CMAKE_SHARED_MODULE_PREFIX.rst
@@ -5,4 +5,4 @@ The prefix for loadable modules that you link to.
The prefix to use for the name of a loadable module on this platform.
-CMAKE_SHARED_MODULE_PREFIX_<LANG> overrides this for language <LANG>.
+``CMAKE_SHARED_MODULE_PREFIX_<LANG>`` overrides this for language ``<LANG>``.
diff --git a/Help/variable/CMAKE_SHARED_MODULE_SUFFIX.rst b/Help/variable/CMAKE_SHARED_MODULE_SUFFIX.rst
index 32a3c34..81515c3 100644
--- a/Help/variable/CMAKE_SHARED_MODULE_SUFFIX.rst
+++ b/Help/variable/CMAKE_SHARED_MODULE_SUFFIX.rst
@@ -6,4 +6,4 @@ The suffix for shared libraries that you link to.
The suffix to use for the end of a loadable module filename on this
platform
-CMAKE_SHARED_MODULE_SUFFIX_<LANG> overrides this for language <LANG>.
+``CMAKE_SHARED_MODULE_SUFFIX_<LANG>`` overrides this for language ``<LANG>``.
diff --git a/Help/variable/CMAKE_SIZEOF_VOID_P.rst b/Help/variable/CMAKE_SIZEOF_VOID_P.rst
index 98dbed6..f5464d1 100644
--- a/Help/variable/CMAKE_SIZEOF_VOID_P.rst
+++ b/Help/variable/CMAKE_SIZEOF_VOID_P.rst
@@ -1,8 +1,8 @@
CMAKE_SIZEOF_VOID_P
-------------------
-Size of a void pointer.
+Size of a ``void`` pointer.
This is set to the size of a pointer on the target machine, and is determined
-by a try compile. If a 64 bit size is found, then the library search
-path is modified to look for 64 bit libraries first.
+by a try compile. If a 64-bit size is found, then the library search
+path is modified to look for 64-bit libraries first.
diff --git a/Help/variable/CMAKE_SKIP_INSTALL_ALL_DEPENDENCY.rst b/Help/variable/CMAKE_SKIP_INSTALL_ALL_DEPENDENCY.rst
index 33ee8a8..80a68c9 100644
--- a/Help/variable/CMAKE_SKIP_INSTALL_ALL_DEPENDENCY.rst
+++ b/Help/variable/CMAKE_SKIP_INSTALL_ALL_DEPENDENCY.rst
@@ -1,11 +1,11 @@
CMAKE_SKIP_INSTALL_ALL_DEPENDENCY
---------------------------------
-Don't make the install target depend on the all target.
+Don't make the ``install`` target depend on the ``all`` target.
-By default, the "install" target depends on the "all" target. This
-has the effect, that when "make install" is invoked or INSTALL is
-built, first the "all" target is built, then the installation starts.
-If CMAKE_SKIP_INSTALL_ALL_DEPENDENCY is set to TRUE, this dependency
-is not created, so the installation process will start immediately,
+By default, the ``install`` target depends on the ``all`` target. This
+has the effect, that when ``make install`` is invoked or ``INSTALL`` is
+built, first the ``all`` target is built, then the installation starts.
+If :variable:`CMAKE_SKIP_INSTALL_ALL_DEPENDENCY` is set to ``TRUE``, this
+dependency is not created, so the installation process will start immediately,
independent from whether the project has been completely built or not.
diff --git a/Help/variable/CMAKE_SKIP_INSTALL_RPATH.rst b/Help/variable/CMAKE_SKIP_INSTALL_RPATH.rst
index f16b212..cc0ac21 100644
--- a/Help/variable/CMAKE_SKIP_INSTALL_RPATH.rst
+++ b/Help/variable/CMAKE_SKIP_INSTALL_RPATH.rst
@@ -11,4 +11,4 @@ always installed without RPATH, even if RPATH is enabled when
building. This can be useful for example to allow running tests from
the build directory with RPATH enabled before the installation step.
To omit RPATH in both the build and install steps, use
-CMAKE_SKIP_RPATH instead.
+:variable:`CMAKE_SKIP_RPATH` instead.
diff --git a/Help/variable/CMAKE_SKIP_INSTALL_RULES.rst b/Help/variable/CMAKE_SKIP_INSTALL_RULES.rst
index 5eda254..44966f3 100644
--- a/Help/variable/CMAKE_SKIP_INSTALL_RULES.rst
+++ b/Help/variable/CMAKE_SKIP_INSTALL_RULES.rst
@@ -3,5 +3,6 @@ CMAKE_SKIP_INSTALL_RULES
Whether to disable generation of installation rules.
-If TRUE, cmake will neither generate installaton rules nor
-will it generate cmake_install.cmake files. This variable is FALSE by default.
+If ``TRUE``, cmake will neither generate installaton rules nor
+will it generate ``cmake_install.cmake`` files. This variable is ``FALSE`` by
+default.
diff --git a/Help/variable/CMAKE_SKIP_RPATH.rst b/Help/variable/CMAKE_SKIP_RPATH.rst
index c93f67f..d7ce8e4 100644
--- a/Help/variable/CMAKE_SKIP_RPATH.rst
+++ b/Help/variable/CMAKE_SKIP_RPATH.rst
@@ -3,8 +3,8 @@ CMAKE_SKIP_RPATH
If true, do not add run time path information.
-If this is set to TRUE, then the rpath information is not added to
+If this is set to ``TRUE``, then the rpath information is not added to
compiled executables. The default is to add rpath information if the
platform supports it. This allows for easy running from the build
tree. To omit RPATH in the install step, but not the build step, use
-CMAKE_SKIP_INSTALL_RPATH instead.
+:variable:`CMAKE_SKIP_INSTALL_RPATH` instead.
diff --git a/Help/variable/CMAKE_SOURCE_DIR.rst b/Help/variable/CMAKE_SOURCE_DIR.rst
index 088fa83..3df0226 100644
--- a/Help/variable/CMAKE_SOURCE_DIR.rst
+++ b/Help/variable/CMAKE_SOURCE_DIR.rst
@@ -5,4 +5,4 @@ The path to the top level of the source tree.
This is the full path to the top level of the current CMake source
tree. For an in-source build, this would be the same as
-CMAKE_BINARY_DIR.
+:variable:`CMAKE_BINARY_DIR`.
diff --git a/Help/variable/CMAKE_STAGING_PREFIX.rst b/Help/variable/CMAKE_STAGING_PREFIX.rst
index c4de7da..1310e94 100644
--- a/Help/variable/CMAKE_STAGING_PREFIX.rst
+++ b/Help/variable/CMAKE_STAGING_PREFIX.rst
@@ -5,9 +5,10 @@ This variable may be set to a path to install to when cross-compiling. This can
be useful if the path in :variable:`CMAKE_SYSROOT` is read-only, or otherwise
should remain pristine.
-The CMAKE_STAGING_PREFIX location is also used as a search prefix by the ``find_*``
-commands. This can be controlled by setting the :variable:`CMAKE_FIND_NO_INSTALL_PREFIX`
-variable.
+The ``CMAKE_STAGING_PREFIX`` location is also used as a search prefix by the
+``find_*`` commands. This can be controlled by setting the
+:variable:`CMAKE_FIND_NO_INSTALL_PREFIX` variable.
-If any RPATH/RUNPATH entries passed to the linker contain the CMAKE_STAGING_PREFIX,
-the matching path fragments are replaced with the :variable:`CMAKE_INSTALL_PREFIX`.
+If any RPATH/RUNPATH entries passed to the linker contain the
+``CMAKE_STAGING_PREFIX``, the matching path fragments are replaced with the
+:variable:`CMAKE_INSTALL_PREFIX`.
diff --git a/Help/variable/CMAKE_STATIC_LIBRARY_PREFIX.rst b/Help/variable/CMAKE_STATIC_LIBRARY_PREFIX.rst
index 0a3095d..714b5cc 100644
--- a/Help/variable/CMAKE_STATIC_LIBRARY_PREFIX.rst
+++ b/Help/variable/CMAKE_STATIC_LIBRARY_PREFIX.rst
@@ -3,6 +3,6 @@ CMAKE_STATIC_LIBRARY_PREFIX
The prefix for static libraries that you link to.
-The prefix to use for the name of a static library, lib on UNIX.
+The prefix to use for the name of a static library, ``lib`` on UNIX.
-CMAKE_STATIC_LIBRARY_PREFIX_<LANG> overrides this for language <LANG>.
+``CMAKE_STATIC_LIBRARY_PREFIX_<LANG>`` overrides this for language ``<LANG>``.
diff --git a/Help/variable/CMAKE_STATIC_LIBRARY_SUFFIX.rst b/Help/variable/CMAKE_STATIC_LIBRARY_SUFFIX.rst
index 4d07671..28dc09d 100644
--- a/Help/variable/CMAKE_STATIC_LIBRARY_SUFFIX.rst
+++ b/Help/variable/CMAKE_STATIC_LIBRARY_SUFFIX.rst
@@ -3,7 +3,7 @@ CMAKE_STATIC_LIBRARY_SUFFIX
The suffix for static libraries that you link to.
-The suffix to use for the end of a static library filename, .lib on
+The suffix to use for the end of a static library filename, ``.lib`` on
Windows.
-CMAKE_STATIC_LIBRARY_SUFFIX_<LANG> overrides this for language <LANG>.
+``CMAKE_STATIC_LIBRARY_SUFFIX_<LANG>`` overrides this for language ``<LANG>``.
diff --git a/Help/variable/CMAKE_STATIC_LINKER_FLAGS_CONFIG.rst b/Help/variable/CMAKE_STATIC_LINKER_FLAGS_CONFIG.rst
index 6cde24d..b9f8003 100644
--- a/Help/variable/CMAKE_STATIC_LINKER_FLAGS_CONFIG.rst
+++ b/Help/variable/CMAKE_STATIC_LINKER_FLAGS_CONFIG.rst
@@ -3,5 +3,5 @@ CMAKE_STATIC_LINKER_FLAGS_<CONFIG>
Flags to be used when linking a static library.
-Same as CMAKE_C_FLAGS_* but used by the linker when creating static
+Same as ``CMAKE_C_FLAGS_*`` but used by the linker when creating static
libraries.
diff --git a/Help/variable/CMAKE_SYSTEM.rst b/Help/variable/CMAKE_SYSTEM.rst
index 23f5980..c7d0d8a 100644
--- a/Help/variable/CMAKE_SYSTEM.rst
+++ b/Help/variable/CMAKE_SYSTEM.rst
@@ -1,7 +1,7 @@
CMAKE_SYSTEM
------------
-Composit Name of OS CMake is compiling for.
+Composite name of operating system CMake is compiling for.
This variable is the composite of :variable:`CMAKE_SYSTEM_NAME` and
:variable:`CMAKE_SYSTEM_VERSION`, e.g.
diff --git a/Help/variable/CMAKE_SYSTEM_NAME.rst b/Help/variable/CMAKE_SYSTEM_NAME.rst
index 189dc18..0466da4 100644
--- a/Help/variable/CMAKE_SYSTEM_NAME.rst
+++ b/Help/variable/CMAKE_SYSTEM_NAME.rst
@@ -1,8 +1,8 @@
CMAKE_SYSTEM_NAME
-----------------
-Name of the OS CMake is building for.
+Name of the operating system CMake is building for.
-This is the name of the OS on which CMake is targeting. This variable
-is the same as :variable:`CMAKE_HOST_SYSTEM_NAME` if you build for the
+This is the name of the operating system on which CMake is targeting. This
+variable is the same as :variable:`CMAKE_HOST_SYSTEM_NAME` if you build for the
host system instead of the target system when cross compiling.
diff --git a/Help/variable/CMAKE_SYSTEM_PROCESSOR.rst b/Help/variable/CMAKE_SYSTEM_PROCESSOR.rst
index 2f5313b..09280de 100644
--- a/Help/variable/CMAKE_SYSTEM_PROCESSOR.rst
+++ b/Help/variable/CMAKE_SYSTEM_PROCESSOR.rst
@@ -7,4 +7,4 @@ This variable is the same as :variable:`CMAKE_HOST_SYSTEM_PROCESSOR` if
you build for the host system instead of the target system when
cross compiling.
-* The Green Hills MULTI generator sets this to ``ARM`` by default
+* The :generator:`Green Hills MULTI` generator sets this to ``ARM`` by default.
diff --git a/Help/variable/CMAKE_SYSTEM_VERSION.rst b/Help/variable/CMAKE_SYSTEM_VERSION.rst
index 33510bb..3b3cdc5 100644
--- a/Help/variable/CMAKE_SYSTEM_VERSION.rst
+++ b/Help/variable/CMAKE_SYSTEM_VERSION.rst
@@ -1,7 +1,7 @@
CMAKE_SYSTEM_VERSION
--------------------
-The OS version CMake is building for.
+The operating system version CMake is building for.
This variable is the same as :variable:`CMAKE_HOST_SYSTEM_VERSION` if
you build for the host system instead of the target system when
diff --git a/Help/variable/CMAKE_TOOLCHAIN_FILE.rst b/Help/variable/CMAKE_TOOLCHAIN_FILE.rst
index e1a65e1..168ee74 100644
--- a/Help/variable/CMAKE_TOOLCHAIN_FILE.rst
+++ b/Help/variable/CMAKE_TOOLCHAIN_FILE.rst
@@ -4,6 +4,6 @@ CMAKE_TOOLCHAIN_FILE
Path to toolchain file supplied to :manual:`cmake(1)`.
This variable is specified on the command line when cross-compiling with CMake.
-It is the path to a file which is read early in the CMake run and which specifies
-locations for compilers and toolchain utilities, and other target platform and
-compiler related information.
+It is the path to a file which is read early in the CMake run and which
+specifies locations for compilers and toolchain utilities, and other target
+platform and compiler related information.
diff --git a/Help/variable/CMAKE_TRY_COMPILE_CONFIGURATION.rst b/Help/variable/CMAKE_TRY_COMPILE_CONFIGURATION.rst
index a92feab..d731f02 100644
--- a/Help/variable/CMAKE_TRY_COMPILE_CONFIGURATION.rst
+++ b/Help/variable/CMAKE_TRY_COMPILE_CONFIGURATION.rst
@@ -1,9 +1,10 @@
CMAKE_TRY_COMPILE_CONFIGURATION
-------------------------------
-Build configuration used for try_compile and try_run projects.
+Build configuration used for :command:`try_compile` and :command:`try_run`
+projects.
-Projects built by try_compile and try_run are built synchronously
-during the CMake configuration step. Therefore a specific build
+Projects built by :command:`try_compile` and :command:`try_run` are built
+synchronously during the CMake configuration step. Therefore a specific build
configuration must be chosen even if the generated build system
supports multiple configurations.
diff --git a/Help/variable/CMAKE_USER_MAKE_RULES_OVERRIDE.rst b/Help/variable/CMAKE_USER_MAKE_RULES_OVERRIDE.rst
index 5a4c86b..9af0d97 100644
--- a/Help/variable/CMAKE_USER_MAKE_RULES_OVERRIDE.rst
+++ b/Help/variable/CMAKE_USER_MAKE_RULES_OVERRIDE.rst
@@ -4,20 +4,20 @@ CMAKE_USER_MAKE_RULES_OVERRIDE
Specify a CMake file that overrides platform information.
CMake loads the specified file while enabling support for each
-language from either the project() or enable_language() commands. It
-is loaded after CMake's builtin compiler and platform information
+language from either the :command:`project` or :command:`enable_language`
+commands. It is loaded after CMake's builtin compiler and platform information
modules have been loaded but before the information is used. The file
may set platform information variables to override CMake's defaults.
This feature is intended for use only in overriding information
variables that must be set before CMake builds its first test project
to check that the compiler for a language works. It should not be
-used to load a file in cases that a normal include() will work. Use
+used to load a file in cases that a normal :command:`include` will work. Use
it only as a last resort for behavior that cannot be achieved any
-other way. For example, one may set CMAKE_C_FLAGS_INIT to change the
-default value used to initialize CMAKE_C_FLAGS before it is cached.
-The override file should NOT be used to set anything that could be set
-after languages are enabled, such as variables like
-CMAKE_RUNTIME_OUTPUT_DIRECTORY that affect the placement of binaries.
-Information set in the file will be used for try_compile and try_run
-builds too.
+other way. For example, one may set ``CMAKE_C_FLAGS_INIT`` to change the
+default value used to initialize :variable:`CMAKE_C_FLAGS <CMAKE_<LANG>_FLAGS>`
+before it is cached. The override file should NOT be used to set anything
+that could be set after languages are enabled, such as variables like
+:variable:`CMAKE_RUNTIME_OUTPUT_DIRECTORY` that affect the placement of
+binaries. Information set in the file will be used for :command:`try_compile`
+and :command:`try_run` builds too.
diff --git a/Help/variable/CMAKE_USER_MAKE_RULES_OVERRIDE_LANG.rst b/Help/variable/CMAKE_USER_MAKE_RULES_OVERRIDE_LANG.rst
index e6d2c68..e7139ac 100644
--- a/Help/variable/CMAKE_USER_MAKE_RULES_OVERRIDE_LANG.rst
+++ b/Help/variable/CMAKE_USER_MAKE_RULES_OVERRIDE_LANG.rst
@@ -1,7 +1,8 @@
CMAKE_USER_MAKE_RULES_OVERRIDE_<LANG>
-------------------------------------
-Specify a CMake file that overrides platform information for <LANG>.
+Specify a CMake file that overrides platform information for ``<LANG>``.
-This is a language-specific version of CMAKE_USER_MAKE_RULES_OVERRIDE
-loaded only when enabling language <LANG>.
+This is a language-specific version of
+:variable:`CMAKE_USER_MAKE_RULES_OVERRIDE` loaded only when enabling language
+``<LANG>``.
diff --git a/Help/variable/CMAKE_VERBOSE_MAKEFILE.rst b/Help/variable/CMAKE_VERBOSE_MAKEFILE.rst
index 2420a25..232a2fd 100644
--- a/Help/variable/CMAKE_VERBOSE_MAKEFILE.rst
+++ b/Help/variable/CMAKE_VERBOSE_MAKEFILE.rst
@@ -3,7 +3,7 @@ CMAKE_VERBOSE_MAKEFILE
Enable verbose output from Makefile builds.
-This variable is a cache entry initialized (to FALSE) by
+This variable is a cache entry initialized (to ``FALSE``) by
the :command:`project` command. Users may enable the option
in their local build tree to get more verbose output from
Makefile builds and show each command line as it is launched.
diff --git a/Help/variable/CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD.rst b/Help/variable/CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD.rst
index 68f1ff6..f54472a 100644
--- a/Help/variable/CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD.rst
+++ b/Help/variable/CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD.rst
@@ -1,8 +1,8 @@
CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD
-----------------------------------------
-Include INSTALL target to default build.
+Include ``INSTALL`` target to default build.
-In Visual Studio solution, by default the INSTALL target will not be part of
-the default build. Setting this variable will enable the INSTALL target to be
-part of the default build.
+In Visual Studio solution, by default the ``INSTALL`` target will not be part
+of the default build. Setting this variable will enable the ``INSTALL`` target
+to be part of the default build.
diff --git a/Help/variable/CMAKE_VS_INTEL_Fortran_PROJECT_VERSION.rst b/Help/variable/CMAKE_VS_INTEL_Fortran_PROJECT_VERSION.rst
index 7e9d317..0be10e5 100644
--- a/Help/variable/CMAKE_VS_INTEL_Fortran_PROJECT_VERSION.rst
+++ b/Help/variable/CMAKE_VS_INTEL_Fortran_PROJECT_VERSION.rst
@@ -1,7 +1,7 @@
CMAKE_VS_INTEL_Fortran_PROJECT_VERSION
--------------------------------------
-When generating for Visual Studio 7 or greater with the Intel Fortran
-plugin installed, this specifies the .vfproj project file format
+When generating for :generator:`Visual Studio 7` or greater with the Intel
+Fortran plugin installed, this specifies the ``.vfproj`` project file format
version. This is intended for internal use by CMake and should not be
used by project code.
diff --git a/Help/variable/CMAKE_VS_PLATFORM_TOOLSET.rst b/Help/variable/CMAKE_VS_PLATFORM_TOOLSET.rst
index 08c6061..144a41d 100644
--- a/Help/variable/CMAKE_VS_PLATFORM_TOOLSET.rst
+++ b/Help/variable/CMAKE_VS_PLATFORM_TOOLSET.rst
@@ -5,6 +5,6 @@ Visual Studio Platform Toolset name.
VS 10 and above use MSBuild under the hood and support multiple
compiler toolchains. CMake may specify a toolset explicitly, such as
-"v110" for VS 11 or "Windows7.1SDK" for 64-bit support in VS 10
+``v110`` for VS 11 or ``Windows7.1SDK`` for 64-bit support in VS 10
Express. CMake provides the name of the chosen toolset in this
variable.
diff --git a/Help/variable/CMAKE_WARN_DEPRECATED.rst b/Help/variable/CMAKE_WARN_DEPRECATED.rst
index 7b2510b..662cbd8 100644
--- a/Help/variable/CMAKE_WARN_DEPRECATED.rst
+++ b/Help/variable/CMAKE_WARN_DEPRECATED.rst
@@ -3,5 +3,5 @@ CMAKE_WARN_DEPRECATED
Whether to issue deprecation warnings for macros and functions.
-If TRUE, this can be used by macros and functions to issue deprecation
-warnings. This variable is FALSE by default.
+If ``TRUE``, this can be used by macros and functions to issue deprecation
+warnings. This variable is ``FALSE`` by default.
diff --git a/Help/variable/CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION.rst b/Help/variable/CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION.rst
index f6a188d..81c1158 100644
--- a/Help/variable/CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION.rst
+++ b/Help/variable/CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION.rst
@@ -1,8 +1,9 @@
CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION
------------------------------------------
-Ask cmake_install.cmake script to warn each time a file with absolute INSTALL DESTINATION is encountered.
+Ask ``cmake_install.cmake`` script to warn each time a file with absolute
+``INSTALL DESTINATION`` is encountered.
-This variable is used by CMake-generated cmake_install.cmake scripts.
-If one sets this variable to ON while running the script, it may get
+This variable is used by CMake-generated ``cmake_install.cmake`` scripts.
+If one sets this variable to ``ON`` while running the script, it may get
warning messages from the script.
diff --git a/Help/variable/CMAKE_WIN32_EXECUTABLE.rst b/Help/variable/CMAKE_WIN32_EXECUTABLE.rst
index 3e1e0dd..b96abba 100644
--- a/Help/variable/CMAKE_WIN32_EXECUTABLE.rst
+++ b/Help/variable/CMAKE_WIN32_EXECUTABLE.rst
@@ -1,7 +1,7 @@
CMAKE_WIN32_EXECUTABLE
----------------------
-Default value for WIN32_EXECUTABLE of targets.
+Default value for :prop_tgt:`WIN32_EXECUTABLE` of targets.
-This variable is used to initialize the WIN32_EXECUTABLE property on
-all the targets. See that target property for additional information.
+This variable is used to initialize the :prop_tgt:`WIN32_EXECUTABLE` property
+on all the targets. See that target property for additional information.
diff --git a/Help/variable/CMAKE_XCODE_ATTRIBUTE_an-attribute.rst b/Help/variable/CMAKE_XCODE_ATTRIBUTE_an-attribute.rst
index 096f64e..122b9f6 100644
--- a/Help/variable/CMAKE_XCODE_ATTRIBUTE_an-attribute.rst
+++ b/Help/variable/CMAKE_XCODE_ATTRIBUTE_an-attribute.rst
@@ -3,8 +3,8 @@ CMAKE_XCODE_ATTRIBUTE_<an-attribute>
Set Xcode target attributes directly.
-Tell the Xcode generator to set '<an-attribute>' to a given value in
-the generated Xcode project. Ignored on other generators.
+Tell the :generator:`Xcode` generator to set '<an-attribute>' to a given value
+in the generated Xcode project. Ignored on other generators.
See the :prop_tgt:`XCODE_ATTRIBUTE_<an-attribute>` target property
to set attributes on a specific target.
diff --git a/Help/variable/CMAKE_XCODE_PLATFORM_TOOLSET.rst b/Help/variable/CMAKE_XCODE_PLATFORM_TOOLSET.rst
index f0a4841..210da52 100644
--- a/Help/variable/CMAKE_XCODE_PLATFORM_TOOLSET.rst
+++ b/Help/variable/CMAKE_XCODE_PLATFORM_TOOLSET.rst
@@ -3,7 +3,7 @@ CMAKE_XCODE_PLATFORM_TOOLSET
Xcode compiler selection.
-Xcode supports selection of a compiler from one of the installed
+:generator:`Xcode` supports selection of a compiler from one of the installed
toolsets. CMake provides the name of the chosen toolset in this
-variable, if any is explicitly selected (e.g. via the cmake -T
-option).
+variable, if any is explicitly selected (e.g. via the :manual:`cmake(1)`
+``-T`` option).
diff --git a/Help/variable/CPACK_ABSOLUTE_DESTINATION_FILES.rst b/Help/variable/CPACK_ABSOLUTE_DESTINATION_FILES.rst
index d836629..928fe45 100644
--- a/Help/variable/CPACK_ABSOLUTE_DESTINATION_FILES.rst
+++ b/Help/variable/CPACK_ABSOLUTE_DESTINATION_FILES.rst
@@ -1,10 +1,10 @@
CPACK_ABSOLUTE_DESTINATION_FILES
--------------------------------
-List of files which have been installed using an ABSOLUTE DESTINATION path.
+List of files which have been installed using an ``ABSOLUTE DESTINATION`` path.
This variable is a Read-Only variable which is set internally by CPack
during installation and before packaging using
-CMAKE_ABSOLUTE_DESTINATION_FILES defined in cmake_install.cmake
+:variable:`CMAKE_ABSOLUTE_DESTINATION_FILES` defined in ``cmake_install.cmake``
scripts. The value can be used within CPack project configuration
-file and/or CPack<GEN>.cmake file of <GEN> generator.
+file and/or ``CPack<GEN>.cmake`` file of ``<GEN>`` generator.
diff --git a/Help/variable/CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY.rst b/Help/variable/CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY.rst
index e938978..6cf75e4 100644
--- a/Help/variable/CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY.rst
+++ b/Help/variable/CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY.rst
@@ -3,6 +3,6 @@ CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY
Boolean toggle to include/exclude top level directory (component case).
-Similar usage as CPACK_INCLUDE_TOPLEVEL_DIRECTORY but for the
-component case. See CPACK_INCLUDE_TOPLEVEL_DIRECTORY documentation
-for the detail.
+Similar usage as :variable:`CPACK_INCLUDE_TOPLEVEL_DIRECTORY` but for the
+component case. See :variable:`CPACK_INCLUDE_TOPLEVEL_DIRECTORY`
+documentation for the detail.
diff --git a/Help/variable/CPACK_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION.rst b/Help/variable/CPACK_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION.rst
index 4d96385..5dad6bd 100644
--- a/Help/variable/CPACK_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION.rst
+++ b/Help/variable/CPACK_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION.rst
@@ -1,10 +1,11 @@
CPACK_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION
-------------------------------------------
-Ask CPack to error out as soon as a file with absolute INSTALL DESTINATION is encountered.
+Ask CPack to error out as soon as a file with absolute ``INSTALL DESTINATION``
+is encountered.
The fatal error is emitted before the installation of the offending
-file takes place. Some CPack generators, like NSIS,enforce this
+file takes place. Some CPack generators, like NSIS, enforce this
internally. This variable triggers the definition
-ofCMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION when CPack runsVariables
-common to all CPack generators
+of :variable:`CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION` when CPack
+runs.
diff --git a/Help/variable/CPACK_INCLUDE_TOPLEVEL_DIRECTORY.rst b/Help/variable/CPACK_INCLUDE_TOPLEVEL_DIRECTORY.rst
index 4f96bff..b8e9105 100644
--- a/Help/variable/CPACK_INCLUDE_TOPLEVEL_DIRECTORY.rst
+++ b/Help/variable/CPACK_INCLUDE_TOPLEVEL_DIRECTORY.rst
@@ -4,16 +4,17 @@ CPACK_INCLUDE_TOPLEVEL_DIRECTORY
Boolean toggle to include/exclude top level directory.
When preparing a package CPack installs the item under the so-called
-top level directory. The purpose of is to include (set to 1 or ON or
-TRUE) the top level directory in the package or not (set to 0 or OFF
-or FALSE).
+top level directory. The purpose of is to include (set to ``1`` or ``ON`` or
+``TRUE``) the top level directory in the package or not (set to ``0`` or
+``OFF`` or ``FALSE``).
Each CPack generator has a built-in default value for this variable.
E.g. Archive generators (ZIP, TGZ, ...) includes the top level
whereas RPM or DEB don't. The user may override the default value by
setting this variable.
-There is a similar variable CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY
-which may be used to override the behavior for the component packaging
+There is a similar variable
+:variable:`CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY` which may be used
+to override the behavior for the component packaging
case which may have different default value for historical (now
backward compatibility) reason.
diff --git a/Help/variable/CPACK_INSTALL_SCRIPT.rst b/Help/variable/CPACK_INSTALL_SCRIPT.rst
index 59b8cd7..12a48a4 100644
--- a/Help/variable/CPACK_INSTALL_SCRIPT.rst
+++ b/Help/variable/CPACK_INSTALL_SCRIPT.rst
@@ -5,4 +5,4 @@ Extra CMake script provided by the user.
If set this CMake script will be executed by CPack during its local
[CPack-private] installation which is done right before packaging the
-files. The script is not called by e.g.: make install.
+files. The script is not called by e.g.: ``make install``.
diff --git a/Help/variable/CPACK_PACKAGING_INSTALL_PREFIX.rst b/Help/variable/CPACK_PACKAGING_INSTALL_PREFIX.rst
index f9cfa1b..f423e2e 100644
--- a/Help/variable/CPACK_PACKAGING_INSTALL_PREFIX.rst
+++ b/Help/variable/CPACK_PACKAGING_INSTALL_PREFIX.rst
@@ -3,11 +3,13 @@ CPACK_PACKAGING_INSTALL_PREFIX
The prefix used in the built package.
-Each CPack generator has a default value (like /usr). This default
-value may be overwritten from the CMakeLists.txt or the cpack command
-line by setting an alternative value.
+Each CPack generator has a default value (like ``/usr``). This default
+value may be overwritten from the ``CMakeLists.txt`` or the :manual:`cpack(1)`
+command line by setting an alternative value. Example:
-e.g. set(CPACK_PACKAGING_INSTALL_PREFIX "/opt")
+::
-This is not the same purpose as CMAKE_INSTALL_PREFIX which is used
+ set(CPACK_PACKAGING_INSTALL_PREFIX "/opt")
+
+This is not the same purpose as :variable:`CMAKE_INSTALL_PREFIX` which is used
when installing from the build tree without building a package.
diff --git a/Help/variable/CPACK_SET_DESTDIR.rst b/Help/variable/CPACK_SET_DESTDIR.rst
index 69d82e6..27fd355 100644
--- a/Help/variable/CPACK_SET_DESTDIR.rst
+++ b/Help/variable/CPACK_SET_DESTDIR.rst
@@ -1,30 +1,31 @@
CPACK_SET_DESTDIR
-----------------
-Boolean toggle to make CPack use DESTDIR mechanism when packaging.
+Boolean toggle to make CPack use ``DESTDIR`` mechanism when packaging.
-DESTDIR means DESTination DIRectory. It is commonly used by makefile
+``DESTDIR`` means DESTination DIRectory. It is commonly used by makefile
users in order to install software at non-default location. It is a
basic relocation mechanism that should not be used on Windows (see
-CMAKE_INSTALL_PREFIX documentation). It is usually invoked like this:
+:variable:`CMAKE_INSTALL_PREFIX` documentation). It is usually invoked like
+this:
::
make DESTDIR=/home/john install
which will install the concerned software using the installation
-prefix, e.g. "/usr/local" prepended with the DESTDIR value which
-finally gives "/home/john/usr/local". When preparing a package, CPack
+prefix, e.g. ``/usr/local`` prepended with the ``DESTDIR`` value which
+finally gives ``/home/john/usr/local``. When preparing a package, CPack
first installs the items to be packaged in a local (to the build tree)
-directory by using the same DESTDIR mechanism. Nevertheless, if
-CPACK_SET_DESTDIR is set then CPack will set DESTDIR before doing the
+directory by using the same ``DESTDIR`` mechanism. Nevertheless, if
+``CPACK_SET_DESTDIR`` is set then CPack will set ``DESTDIR`` before doing the
local install. The most noticeable difference is that without
-CPACK_SET_DESTDIR, CPack uses CPACK_PACKAGING_INSTALL_PREFIX as a
-prefix whereas with CPACK_SET_DESTDIR set, CPack will use
-CMAKE_INSTALL_PREFIX as a prefix.
+``CPACK_SET_DESTDIR``, CPack uses :variable:`CPACK_PACKAGING_INSTALL_PREFIX`
+as a prefix whereas with ``CPACK_SET_DESTDIR`` set, CPack will use
+:variable:`CMAKE_INSTALL_PREFIX` as a prefix.
-Manually setting CPACK_SET_DESTDIR may help (or simply be necessary)
-if some install rules uses absolute DESTINATION (see CMake INSTALL
-command). However, starting with CPack/CMake 2.8.3 RPM and DEB
-installers tries to handle DESTDIR automatically so that it is seldom
-necessary for the user to set it.
+Manually setting ``CPACK_SET_DESTDIR`` may help (or simply be necessary)
+if some install rules uses absolute ``DESTINATION`` (see CMake
+:command:`install` command). However, starting with CPack/CMake 2.8.3 RPM
+and DEB installers tries to handle ``DESTDIR`` automatically so that it is
+seldom necessary for the user to set it.
diff --git a/Help/variable/CPACK_WARN_ON_ABSOLUTE_INSTALL_DESTINATION.rst b/Help/variable/CPACK_WARN_ON_ABSOLUTE_INSTALL_DESTINATION.rst
index 8d6f54f..3fc5cca 100644
--- a/Help/variable/CPACK_WARN_ON_ABSOLUTE_INSTALL_DESTINATION.rst
+++ b/Help/variable/CPACK_WARN_ON_ABSOLUTE_INSTALL_DESTINATION.rst
@@ -1,8 +1,9 @@
CPACK_WARN_ON_ABSOLUTE_INSTALL_DESTINATION
------------------------------------------
-Ask CPack to warn each time a file with absolute INSTALL DESTINATION is encountered.
+Ask CPack to warn each time a file with absolute ``INSTALL DESTINATION`` is
+encountered.
This variable triggers the definition of
-CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION when CPack runs
-cmake_install.cmake scripts.
+:variable:`CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION` when CPack runs
+``cmake_install.cmake`` scripts.
diff --git a/Help/variable/CTEST_COVERAGE_COMMAND.rst b/Help/variable/CTEST_COVERAGE_COMMAND.rst
index a669dd7..0491d42 100644
--- a/Help/variable/CTEST_COVERAGE_COMMAND.rst
+++ b/Help/variable/CTEST_COVERAGE_COMMAND.rst
@@ -12,12 +12,12 @@ Java project can generate a series of XML files.
The Cobertura Coverage parser expects to read the coverage data from a
single XML file which contains the coverage data for all modules.
-Cobertura has a program with the ability to merge given cobertura.ser files
+Cobertura has a program with the ability to merge given ``cobertura.ser`` files
and then another program to generate a combined XML file from the previous
merged file. For command line testing, this can be done by hand prior to
CTest looking for the coverage files. For script builds,
set the ``CTEST_COVERAGE_COMMAND`` variable to point to a file which will
-perform these same steps, such as a .sh or .bat file.
+perform these same steps, such as a ``.sh`` or ``.bat`` file.
.. code-block:: cmake
@@ -35,17 +35,17 @@ the :command:`configure_file` command and might contain the following code:
cobertura-report --datafile coberturamerge.ser --destination . \
--format xml $SourceDirs
-The script uses ``find`` to capture the paths to all of the cobertura.ser files
-found below the project's source directory. It keeps the list of files and
-supplies it as an argument to the ``cobertura-merge`` program. The ``--datafile``
-argument signifies where the result of the merge will be kept.
+The script uses ``find`` to capture the paths to all of the ``cobertura.ser``
+files found below the project's source directory. It keeps the list of files
+and supplies it as an argument to the ``cobertura-merge`` program. The
+``--datafile`` argument signifies where the result of the merge will be kept.
The combined ``coberturamerge.ser`` file is then used to generate the XML report
-using the ``cobertura-report`` program. The call to the cobertura-report program
-requires some named arguments.
+using the ``cobertura-report`` program. The call to the cobertura-report
+program requires some named arguments.
``--datafila``
- path to the merged .ser file
+ path to the merged ``.ser`` file
``--destination``
path to put the output files(s)
@@ -54,7 +54,7 @@ requires some named arguments.
file format to write output in: xml or html
The rest of the supplied arguments consist of the full paths to the
-/src/main/java directories of each module within the souce tree. These
+``/src/main/java`` directories of each module within the souce tree. These
directories are needed and should not be forgotten.
.. _`Cobertura`: http://cobertura.github.io/cobertura/
diff --git a/Help/variable/CTEST_MEMORYCHECK_TYPE.rst b/Help/variable/CTEST_MEMORYCHECK_TYPE.rst
index f1087c0..b963293 100644
--- a/Help/variable/CTEST_MEMORYCHECK_TYPE.rst
+++ b/Help/variable/CTEST_MEMORYCHECK_TYPE.rst
@@ -3,5 +3,6 @@ CTEST_MEMORYCHECK_TYPE
Specify the CTest ``MemoryCheckType`` setting
in a :manual:`ctest(1)` dashboard client script.
-Valid values are Valgrind, Purify, BoundsChecker, and ThreadSanitizer,
-AddressSanitizer, MemorySanitizer, and UndefinedBehaviorSanitizer.
+Valid values are ``Valgrind``, ``Purify``, ``BoundsChecker``, and
+``ThreadSanitizer``, ``AddressSanitizer``, ``MemorySanitizer``, and
+``UndefinedBehaviorSanitizer``.
diff --git a/Help/variable/CYGWIN.rst b/Help/variable/CYGWIN.rst
index c168878..0039e07 100644
--- a/Help/variable/CYGWIN.rst
+++ b/Help/variable/CYGWIN.rst
@@ -1,6 +1,6 @@
CYGWIN
------
-True for Cygwin.
+``True`` for Cygwin.
-Set to true when using Cygwin.
+Set to ``true`` when using Cygwin.
diff --git a/Help/variable/ENV.rst b/Help/variable/ENV.rst
index 977afc3..368152a 100644
--- a/Help/variable/ENV.rst
+++ b/Help/variable/ENV.rst
@@ -3,5 +3,5 @@ ENV
Access environment variables.
-Use the syntax $ENV{VAR} to read environment variable VAR. See also
-the set() command to set ENV{VAR}.
+Use the syntax ``$ENV{VAR}`` to read environment variable ``VAR``. See also
+the :command:`set` command to set ``ENV{VAR}``.
diff --git a/Help/variable/EXECUTABLE_OUTPUT_PATH.rst b/Help/variable/EXECUTABLE_OUTPUT_PATH.rst
index 7079230..26d3e92 100644
--- a/Help/variable/EXECUTABLE_OUTPUT_PATH.rst
+++ b/Help/variable/EXECUTABLE_OUTPUT_PATH.rst
@@ -3,6 +3,6 @@ EXECUTABLE_OUTPUT_PATH
Old executable location variable.
-The target property RUNTIME_OUTPUT_DIRECTORY supercedes this variable
-for a target if it is set. Executable targets are otherwise placed in
+The target property :prop_tgt:`RUNTIME_OUTPUT_DIRECTORY` supercedes this
+variable for a target if it is set. Executable targets are otherwise placed in
this directory.
diff --git a/Help/variable/LIBRARY_OUTPUT_PATH.rst b/Help/variable/LIBRARY_OUTPUT_PATH.rst
index 1c1f8ae..ba02911 100644
--- a/Help/variable/LIBRARY_OUTPUT_PATH.rst
+++ b/Help/variable/LIBRARY_OUTPUT_PATH.rst
@@ -3,7 +3,7 @@ LIBRARY_OUTPUT_PATH
Old library location variable.
-The target properties ARCHIVE_OUTPUT_DIRECTORY,
-LIBRARY_OUTPUT_DIRECTORY, and RUNTIME_OUTPUT_DIRECTORY supercede this
-variable for a target if they are set. Library targets are otherwise
-placed in this directory.
+The target properties :prop_tgt:`ARCHIVE_OUTPUT_DIRECTORY`,
+:prop_tgt:`LIBRARY_OUTPUT_DIRECTORY`, and :prop_tgt:`RUNTIME_OUTPUT_DIRECTORY`
+supercede this variable for a target if they are set. Library targets are
+otherwise placed in this directory.
diff --git a/Help/variable/MINGW.rst b/Help/variable/MINGW.rst
index 521d417..6d29be4 100644
--- a/Help/variable/MINGW.rst
+++ b/Help/variable/MINGW.rst
@@ -1,6 +1,6 @@
MINGW
-----
-True when using MinGW
+``True`` when using MinGW
-Set to true when the compiler is some version of MinGW.
+Set to ``true`` when the compiler is some version of MinGW.
diff --git a/Help/variable/MSVC.rst b/Help/variable/MSVC.rst
index e9f931b..913ed08 100644
--- a/Help/variable/MSVC.rst
+++ b/Help/variable/MSVC.rst
@@ -1,6 +1,6 @@
MSVC
----
-True when using Microsoft Visual C
+``True`` when using Microsoft Visual C++.
-Set to true when the compiler is some version of Microsoft Visual C.
+Set to ``true`` when the compiler is some version of Microsoft Visual C++.
diff --git a/Help/variable/MSVC10.rst b/Help/variable/MSVC10.rst
index 894c5aa..33692ad 100644
--- a/Help/variable/MSVC10.rst
+++ b/Help/variable/MSVC10.rst
@@ -1,6 +1,6 @@
MSVC10
------
-True when using Microsoft Visual C 10.0
+``True`` when using Microsoft Visual C++ 10.0
-Set to true when the compiler is version 10.0 of Microsoft Visual C.
+Set to ``true`` when the compiler is version 10.0 of Microsoft Visual C++.
diff --git a/Help/variable/MSVC11.rst b/Help/variable/MSVC11.rst
index fe25297..3ab606d 100644
--- a/Help/variable/MSVC11.rst
+++ b/Help/variable/MSVC11.rst
@@ -1,6 +1,6 @@
MSVC11
------
-True when using Microsoft Visual C 11.0
+``True`` when using Microsoft Visual C++ 11.0
-Set to true when the compiler is version 11.0 of Microsoft Visual C.
+Set to ``true`` when the compiler is version 11.0 of Microsoft Visual C++.
diff --git a/Help/variable/MSVC12.rst b/Help/variable/MSVC12.rst
index 216d3d3..15fa64b 100644
--- a/Help/variable/MSVC12.rst
+++ b/Help/variable/MSVC12.rst
@@ -1,6 +1,6 @@
MSVC12
------
-True when using Microsoft Visual C 12.0
+``True`` when using Microsoft Visual C++ 12.0.
-Set to true when the compiler is version 12.0 of Microsoft Visual C.
+Set to ``true`` when the compiler is version 12.0 of Microsoft Visual C++.
diff --git a/Help/variable/MSVC14.rst b/Help/variable/MSVC14.rst
index 33c782b..0b9125d 100644
--- a/Help/variable/MSVC14.rst
+++ b/Help/variable/MSVC14.rst
@@ -1,6 +1,6 @@
MSVC14
------
-True when using Microsoft Visual C 14.0
+``True`` when using Microsoft Visual C++ 14.0.
-Set to true when the compiler is version 14.0 of Microsoft Visual C.
+Set to ``true`` when the compiler is version 14.0 of Microsoft Visual C++.
diff --git a/Help/variable/MSVC60.rst b/Help/variable/MSVC60.rst
index 572e9f4..14f09cf 100644
--- a/Help/variable/MSVC60.rst
+++ b/Help/variable/MSVC60.rst
@@ -1,6 +1,6 @@
MSVC60
------
-True when using Microsoft Visual C 6.0
+``True`` when using Microsoft Visual C++ 6.0.
-Set to true when the compiler is version 6.0 of Microsoft Visual C.
+Set to ``true`` when the compiler is version 6.0 of Microsoft Visual C++.
diff --git a/Help/variable/MSVC70.rst b/Help/variable/MSVC70.rst
index b1b7a881..76fa96f 100644
--- a/Help/variable/MSVC70.rst
+++ b/Help/variable/MSVC70.rst
@@ -1,6 +1,6 @@
MSVC70
------
-True when using Microsoft Visual C 7.0
+``True`` when using Microsoft Visual C++ 7.0.
-Set to true when the compiler is version 7.0 of Microsoft Visual C.
+Set to ``true`` when the compiler is version 7.0 of Microsoft Visual C++.
diff --git a/Help/variable/MSVC71.rst b/Help/variable/MSVC71.rst
index af309a6..d69d4fc 100644
--- a/Help/variable/MSVC71.rst
+++ b/Help/variable/MSVC71.rst
@@ -1,6 +1,6 @@
MSVC71
------
-True when using Microsoft Visual C 7.1
+``True`` when using Microsoft Visual C++ 7.1.
-Set to true when the compiler is version 7.1 of Microsoft Visual C.
+Set to ``true`` when the compiler is version 7.1 of Microsoft Visual C++.
diff --git a/Help/variable/MSVC80.rst b/Help/variable/MSVC80.rst
index 306c67f..b17777c 100644
--- a/Help/variable/MSVC80.rst
+++ b/Help/variable/MSVC80.rst
@@ -1,6 +1,6 @@
MSVC80
------
-True when using Microsoft Visual C 8.0
+``True`` when using Microsoft Visual C++ 8.0.
-Set to true when the compiler is version 8.0 of Microsoft Visual C.
+Set to ``true`` when the compiler is version 8.0 of Microsoft Visual C++.
diff --git a/Help/variable/MSVC90.rst b/Help/variable/MSVC90.rst
index 3cfcc67..7162d6c 100644
--- a/Help/variable/MSVC90.rst
+++ b/Help/variable/MSVC90.rst
@@ -1,6 +1,6 @@
MSVC90
------
-True when using Microsoft Visual C 9.0
+``True`` when using Microsoft Visual C++ 9.0.
-Set to true when the compiler is version 9.0 of Microsoft Visual C.
+Set to ``true`` when the compiler is version 9.0 of Microsoft Visual C++.
diff --git a/Help/variable/MSVC_IDE.rst b/Help/variable/MSVC_IDE.rst
index 055f876..027d1bc 100644
--- a/Help/variable/MSVC_IDE.rst
+++ b/Help/variable/MSVC_IDE.rst
@@ -1,7 +1,7 @@
MSVC_IDE
--------
-True when using the Microsoft Visual C IDE
+``True`` when using the Microsoft Visual C++ IDE.
-Set to true when the target platform is the Microsoft Visual C IDE, as
+Set to ``true`` when the target platform is the Microsoft Visual C++ IDE, as
opposed to the command line compiler.
diff --git a/Help/variable/UNIX.rst b/Help/variable/UNIX.rst
index 82e3454..0877b7c 100644
--- a/Help/variable/UNIX.rst
+++ b/Help/variable/UNIX.rst
@@ -1,7 +1,7 @@
UNIX
----
-True for UNIX and UNIX like operating systems.
+``True`` for UNIX and UNIX like operating systems.
-Set to true when the target system is UNIX or UNIX like (i.e. APPLE
-and CYGWIN).
+Set to ``true`` when the target system is UNIX or UNIX like (i.e.
+:variable:`APPLE` and :variable:`CYGWIN`).
diff --git a/Help/variable/WIN32.rst b/Help/variable/WIN32.rst
index 8cf7bf3..2189069 100644
--- a/Help/variable/WIN32.rst
+++ b/Help/variable/WIN32.rst
@@ -1,6 +1,6 @@
WIN32
-----
-True on windows systems, including win64.
+``True`` on Windows systems, including Win64.
-Set to true when the target system is Windows.
+Set to ``true`` when the target system is Windows.
diff --git a/Help/variable/XCODE_VERSION.rst b/Help/variable/XCODE_VERSION.rst
index b6f0403..b85d41e 100644
--- a/Help/variable/XCODE_VERSION.rst
+++ b/Help/variable/XCODE_VERSION.rst
@@ -1,7 +1,7 @@
XCODE_VERSION
-------------
-Version of Xcode (Xcode generator only).
+Version of Xcode (:generator:`Xcode` generator only).
Under the Xcode generator, this is the version of Xcode as specified
-in "Xcode.app/Contents/version.plist" (such as "3.1.2").
+in ``Xcode.app/Contents/version.plist`` (such as ``3.1.2``).
diff --git a/Modules/CMakeFortranCompiler.cmake.in b/Modules/CMakeFortranCompiler.cmake.in
index e4c7618..14fdd60 100644
--- a/Modules/CMakeFortranCompiler.cmake.in
+++ b/Modules/CMakeFortranCompiler.cmake.in
@@ -1,6 +1,7 @@
set(CMAKE_Fortran_COMPILER "@CMAKE_Fortran_COMPILER@")
set(CMAKE_Fortran_COMPILER_ARG1 "@CMAKE_Fortran_COMPILER_ARG1@")
set(CMAKE_Fortran_COMPILER_ID "@CMAKE_Fortran_COMPILER_ID@")
+set(CMAKE_Fortran_COMPILER_VERSION "@CMAKE_Fortran_COMPILER_VERSION@")
set(CMAKE_Fortran_PLATFORM_ID "@CMAKE_Fortran_PLATFORM_ID@")
set(CMAKE_Fortran_SIMULATE_ID "@CMAKE_Fortran_SIMULATE_ID@")
set(CMAKE_Fortran_SIMULATE_VERSION "@CMAKE_Fortran_SIMULATE_VERSION@")
diff --git a/Modules/CPackRPM.cmake b/Modules/CPackRPM.cmake
index cb77fb8..7c1db14 100644
--- a/Modules/CPackRPM.cmake
+++ b/Modules/CPackRPM.cmake
@@ -95,6 +95,7 @@
# * Default : CPACK_PACKAGE_VENDOR if set or "unknown"
#
# .. variable:: CPACK_RPM_PACKAGE_URL
+# CPACK_RPM_<component>_PACKAGE_URL
#
# The projects URL.
#
@@ -123,7 +124,55 @@
# compression whereas older cannot use such RPM. Using this one can enforce
# compression type to be used. Possible value are: lzma, xz, bzip2 and gzip.
#
+# .. variable:: CPACK_RPM_PACKAGE_AUTOREQ
+# CPACK_RPM_<component>_PACKAGE_AUTOREQ
+#
+# RPM spec autoreq field.
+#
+# * Mandatory : NO
+# * Default : -
+#
+# May be used to enable (1, yes) or disable (0, no) automatic shared libraries
+# dependency detection. Dependencies are added to requires list.
+#
+# .. note::
+#
+# By defalut automatic dependency detection is enabled by rpm generator.
+#
+# .. variable:: CPACK_RPM_PACKAGE_AUTOPROV
+# CPACK_RPM_<component>_PACKAGE_AUTOPROV
+#
+# RPM spec autoprov field.
+#
+# * Mandatory : NO
+# * Default : -
+#
+# May be used to enable (1, yes) or disable (0, no) automatic listing of shared
+# libraries that are provided by the package. Shared libraries are added to
+# provides list.
+#
+# .. note::
+#
+# By defalut automatic provides detection is enabled by rpm generator.
+#
+# .. variable:: CPACK_RPM_PACKAGE_AUTOREQPROV
+# CPACK_RPM_<component>_PACKAGE_AUTOREQPROV
+#
+# RPM spec autoreqprov field.
+#
+# * Mandatory : NO
+# * Default : -
+#
+# Variable enables/disables autoreq and autoprov at the same time.
+# See :variable:`CPACK_RPM_PACKAGE_AUTOREQ` and :variable:`CPACK_RPM_PACKAGE_AUTOPROV`
+# for more details.
+#
+# .. note::
+#
+# By defalut automatic detection feature is enabled by rpm.
+#
# .. variable:: CPACK_RPM_PACKAGE_REQUIRES
+# CPACK_RPM_<component>_PACKAGE_REQUIRES
#
# RPM spec requires field.
#
@@ -139,7 +188,25 @@
#
# rpm -qp --requires file.rpm
#
+# .. variable:: CPACK_RPM_PACKAGE_CONFLICTS
+# CPACK_RPM_<component>_PACKAGE_CONFLICTS
+#
+# RPM spec conflicts field.
+#
+# * Mandatory : NO
+# * Default : -
+#
+# May be used to set negative RPM dependencies (conflicts). Note that you must enclose
+# the complete requires string between quotes, for example::
+#
+# set(CPACK_RPM_PACKAGE_CONFLICTS "libxml2")
+#
+# The conflicting package list of an RPM file could be printed with::
+#
+# rpm -qp --conflicts file.rpm
+#
# .. variable:: CPACK_RPM_PACKAGE_REQUIRES_PRE
+# CPACK_RPM_<component>_PACKAGE_REQUIRES_PRE
#
# RPM spec requires(pre) field.
#
@@ -152,6 +219,7 @@
# set(CPACK_RPM_PACKAGE_REQUIRES_PRE "shadow-utils, initscripts")
#
# .. variable:: CPACK_RPM_PACKAGE_REQUIRES_POST
+# CPACK_RPM_<component>_PACKAGE_REQUIRES_POST
#
# RPM spec requires(post) field.
#
@@ -165,6 +233,7 @@
#
#
# .. variable:: CPACK_RPM_PACKAGE_REQUIRES_POSTUN
+# CPACK_RPM_<component>_PACKAGE_REQUIRES_POSTUN
#
# RPM spec requires(postun) field.
#
@@ -178,6 +247,7 @@
#
#
# .. variable:: CPACK_RPM_PACKAGE_REQUIRES_PREUN
+# CPACK_RPM_<component>_PACKAGE_REQUIRES_PREUN
#
# RPM spec requires(preun) field.
#
@@ -190,6 +260,7 @@
# set(CPACK_RPM_PACKAGE_REQUIRES_PREUN "shadow-utils, initscripts")
#
# .. variable:: CPACK_RPM_PACKAGE_SUGGESTS
+# CPACK_RPM_<component>_PACKAGE_SUGGESTS
#
# RPM spec suggest field.
#
@@ -200,6 +271,7 @@
# enclose the complete requires string between quotes.
#
# .. variable:: CPACK_RPM_PACKAGE_PROVIDES
+# CPACK_RPM_<component>_PACKAGE_PROVIDES
#
# RPM spec provides field.
#
@@ -212,6 +284,7 @@
# rpm -qp --provides file.rpm
#
# .. variable:: CPACK_RPM_PACKAGE_OBSOLETES
+# CPACK_RPM_<component>_PACKAGE_OBSOLETES
#
# RPM spec obsoletes field.
#
diff --git a/Modules/Compiler/Cray-DetermineCompiler.cmake b/Modules/Compiler/Cray-DetermineCompiler.cmake
index 881b82c..6602294 100644
--- a/Modules/Compiler/Cray-DetermineCompiler.cmake
+++ b/Modules/Compiler/Cray-DetermineCompiler.cmake
@@ -2,5 +2,5 @@
set(_compiler_id_pp_test "defined(_CRAYC)")
set(_compiler_id_version_compute "
-# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(_RELEASE)
+# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(_RELEASE_MAJOR)
# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(_RELEASE_MINOR)")
diff --git a/Modules/Compiler/GNU-DetermineCompiler.cmake b/Modules/Compiler/GNU-DetermineCompiler.cmake
index 261f148..6ddc566 100644
--- a/Modules/Compiler/GNU-DetermineCompiler.cmake
+++ b/Modules/Compiler/GNU-DetermineCompiler.cmake
@@ -3,7 +3,9 @@ set(_compiler_id_pp_test "defined(__GNUC__)")
set(_compiler_id_version_compute "
# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(__GNUC__)
-# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(__GNUC_MINOR__)
+# if defined(__GNUC_MINOR__)
+# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(__GNUC_MINOR__)
+# endif
# if defined(__GNUC_PATCHLEVEL__)
# define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__GNUC_PATCHLEVEL__)
# endif")
diff --git a/Modules/DartConfiguration.tcl.in b/Modules/DartConfiguration.tcl.in
index 918b407..2da8354 100644
--- a/Modules/DartConfiguration.tcl.in
+++ b/Modules/DartConfiguration.tcl.in
@@ -69,6 +69,7 @@ UpdateType: @UPDATE_TYPE@
# Compiler info
Compiler: @CMAKE_CXX_COMPILER@
+CompilerVersion: @CMAKE_CXX_COMPILER_VERSION@
# Dynamic analysis (MemCheck)
PurifyCommand: @PURIFYCOMMAND@
diff --git a/Modules/ExternalProject.cmake b/Modules/ExternalProject.cmake
index f6844be..0fbf7c3 100644
--- a/Modules/ExternalProject.cmake
+++ b/Modules/ExternalProject.cmake
@@ -609,7 +609,7 @@ if(error_code)
endif()
execute_process(
- COMMAND \"${hg_EXECUTABLE}\" clone \"${hg_repository}\" \"${src_name}\"
+ COMMAND \"${hg_EXECUTABLE}\" clone -U \"${hg_repository}\" \"${src_name}\"
WORKING_DIRECTORY \"${work_dir}\"
RESULT_VARIABLE error_code
)
@@ -1211,7 +1211,7 @@ function(_ep_get_build_command name step cmd_var)
if(step STREQUAL "INSTALL")
set(args install)
endif()
- if(step STREQUAL "TEST")
+ if("x${step}x" STREQUAL "xTESTx")
set(args test)
endif()
else()
@@ -1230,7 +1230,7 @@ function(_ep_get_build_command name step cmd_var)
list(APPEND args --target install)
endif()
# But for "TEST" drive the project with corresponding "ctest".
- if(step STREQUAL "TEST")
+ if("x${step}x" STREQUAL "xTESTx")
string(REGEX REPLACE "^(.*/)cmake([^/]*)$" "\\1ctest\\2" cmd "${cmd}")
set(args "")
endif()
@@ -1246,7 +1246,7 @@ function(_ep_get_build_command name step cmd_var)
if(step STREQUAL "INSTALL")
set(args install)
endif()
- if(step STREQUAL "TEST")
+ if("x${step}x" STREQUAL "xTESTx")
set(args test)
endif()
endif()
diff --git a/Modules/FindBoost.cmake b/Modules/FindBoost.cmake
index 05b552a..33e6a49 100644
--- a/Modules/FindBoost.cmake
+++ b/Modules/FindBoost.cmake
@@ -512,13 +512,15 @@ else()
# The user has not requested an exact version. Among known
# versions, find those that are acceptable to the user request.
set(_Boost_KNOWN_VERSIONS ${Boost_ADDITIONAL_VERSIONS}
- "1.58.0" "1.58" "1.57.0" "1.57" "1.56.0" "1.56" "1.55.0" "1.55" "1.54.0" "1.54"
- "1.53.0" "1.53" "1.52.0" "1.52" "1.51.0" "1.51"
+
+ "1.59.0" "1.59" "1.58.0" "1.58" "1.57.0" "1.57" "1.56.0" "1.56" "1.55.0" "1.55"
+ "1.54.0" "1.54" "1.53.0" "1.53" "1.52.0" "1.52" "1.51.0" "1.51"
"1.50.0" "1.50" "1.49.0" "1.49" "1.48.0" "1.48" "1.47.0" "1.47" "1.46.1"
"1.46.0" "1.46" "1.45.0" "1.45" "1.44.0" "1.44" "1.43.0" "1.43" "1.42.0" "1.42"
"1.41.0" "1.41" "1.40.0" "1.40" "1.39.0" "1.39" "1.38.0" "1.38" "1.37.0" "1.37"
"1.36.1" "1.36.0" "1.36" "1.35.1" "1.35.0" "1.35" "1.34.1" "1.34.0"
"1.34" "1.33.1" "1.33.0" "1.33")
+
set(_boost_TEST_VERSIONS)
if(Boost_FIND_VERSION)
set(_Boost_FIND_VERSION_SHORT "${Boost_FIND_VERSION_MAJOR}.${Boost_FIND_VERSION_MINOR}")
diff --git a/Modules/FindJava.cmake b/Modules/FindJava.cmake
index 9e43174..9f87997 100644
--- a/Modules/FindJava.cmake
+++ b/Modules/FindJava.cmake
@@ -8,21 +8,34 @@
# include files and libraries are. The caller may set variable JAVA_HOME
# to specify a Java installation prefix explicitly.
#
+#
+# Specify one or more of the following components as you call this find module. See example below.
+#
+# ::
+#
+# Runtime = User just want to execute some Java byte-compiled
+# Development = Development tools (java, javac, javah and javadoc), includes Runtime component
+# IdlJ = idl compiler for Java
+# JarSigner = signer tool for jar
+#
+#
# This module sets the following result variables:
#
# ::
#
-# Java_JAVA_EXECUTABLE = the full path to the Java runtime
-# Java_JAVAC_EXECUTABLE = the full path to the Java compiler
-# Java_JAVAH_EXECUTABLE = the full path to the Java header generator
-# Java_JAVADOC_EXECUTABLE = the full path to the Java documention generator
-# Java_JAR_EXECUTABLE = the full path to the Java archiver
-# Java_VERSION_STRING = Version of java found, eg. 1.6.0_12
-# Java_VERSION_MAJOR = The major version of the package found.
-# Java_VERSION_MINOR = The minor version of the package found.
-# Java_VERSION_PATCH = The patch version of the package found.
-# Java_VERSION_TWEAK = The tweak version of the package found (after '_')
-# Java_VERSION = This is set to: $major.$minor.$patch(.$tweak)
+# Java_JAVA_EXECUTABLE = the full path to the Java runtime
+# Java_JAVAC_EXECUTABLE = the full path to the Java compiler
+# Java_JAVAH_EXECUTABLE = the full path to the Java header generator
+# Java_JAVADOC_EXECUTABLE = the full path to the Java documention generator
+# Java_IDLJ_EXECUTABLE = the full path to the Java idl compiler
+# Java_JAR_EXECUTABLE = the full path to the Java archiver
+# Java_JARSIGNER_EXECUTABLE = the full path to the Java jar signer
+# Java_VERSION_STRING = Version of java found, eg. 1.6.0_12
+# Java_VERSION_MAJOR = The major version of the package found.
+# Java_VERSION_MINOR = The minor version of the package found.
+# Java_VERSION_PATCH = The patch version of the package found.
+# Java_VERSION_TWEAK = The tweak version of the package found (after '_')
+# Java_VERSION = This is set to: $major.$minor.$patch(.$tweak)
#
#
#
@@ -184,28 +197,61 @@ find_program(Java_JAVADOC_EXECUTABLE
PATHS ${_JAVA_PATHS}
)
+find_program(Java_IDLJ_EXECUTABLE
+ NAMES idlj
+ HINTS ${_JAVA_HINTS}
+ PATHS ${_JAVA_PATHS}
+)
+
+find_program(Java_JARSIGNER_EXECUTABLE
+ NAMES jarsigner
+ HINTS ${_JAVA_HINTS}
+ PATHS ${_JAVA_PATHS}
+)
+
include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
if(Java_FIND_COMPONENTS)
+ set(_JAVA_REQUIRED_VARS)
foreach(component ${Java_FIND_COMPONENTS})
# User just want to execute some Java byte-compiled
- if(component STREQUAL "Runtime")
- find_package_handle_standard_args(Java
- REQUIRED_VARS Java_JAVA_EXECUTABLE
- VERSION_VAR Java_VERSION
- )
+ If(component STREQUAL "Runtime")
+ list(APPEND _JAVA_REQUIRED_VARS Java_JAVA_EXECUTABLE)
+ if(Java_JAVA_EXECUTABLE)
+ set(Java_Runtime_FOUND TRUE)
+ endif()
elseif(component STREQUAL "Development")
- find_package_handle_standard_args(Java
- REQUIRED_VARS Java_JAVA_EXECUTABLE Java_JAR_EXECUTABLE Java_JAVAC_EXECUTABLE
- Java_JAVAH_EXECUTABLE Java_JAVADOC_EXECUTABLE
- VERSION_VAR Java_VERSION
- )
+ list(APPEND _JAVA_REQUIRED_VARS Java_JAVA_EXECUTABLE Java_JAVAC_EXECUTABLE
+ Java_JAVAH_EXECUTABLE Java_JAVADOC_EXECUTABLE)
+ if(Java_JAVA_EXECUTABLE AND Java_JAVAC_EXECUTABLE
+ AND Java_JAVAH_EXECUTABLE AND Java_JAVADOC_EXECUTABLE)
+ set(Java_Development_FOUND TRUE)
+ endif()
+ elseif(component STREQUAL "IdlJ")
+ list(APPEND _JAVA_REQUIRED_VARS Java_IDLJ_EXECUTABLE)
+ if(Java_IdlJ_EXECUTABLE)
+ set(Java_Extra_FOUND TRUE)
+ endif()
+ elseif(component STREQUAL "JarSigner")
+ list(APPEND _JAVA_REQUIRED_VARS Java_JARSIGNER_EXECUTABLE)
+ if(Java_IDLJ_EXECUTABLE)
+ set(Java_JarSigner_FOUND TRUE)
+ endif()
else()
message(FATAL_ERROR "Comp: ${component} is not handled")
endif()
- set(Java_${component}_FOUND TRUE)
endforeach()
+ list (REMOVE_DUPLICATES _JAVA_REQUIRED_VARS)
+ find_package_handle_standard_args(Java
+ REQUIRED_VARS ${_JAVA_REQUIRED_VARS} HANDLE_COMPONENTS
+ VERSION_VAR Java_VERSION
+ )
+ if(Java_FOUND)
+ foreach(component ${Java_FIND_COMPONENTS})
+ set(Java_${component}_FOUND TRUE)
+ endforeach()
+ endif()
else()
- # Check for everything
+ # Check for Development
find_package_handle_standard_args(Java
REQUIRED_VARS Java_JAVA_EXECUTABLE Java_JAR_EXECUTABLE Java_JAVAC_EXECUTABLE
Java_JAVAH_EXECUTABLE Java_JAVADOC_EXECUTABLE
@@ -220,6 +266,8 @@ mark_as_advanced(
Java_JAVAC_EXECUTABLE
Java_JAVAH_EXECUTABLE
Java_JAVADOC_EXECUTABLE
+ Java_IDLJ_EXECUTABLE
+ Java_JARSIGNER_EXECUTABLE
)
# LEGACY
diff --git a/Modules/FindMPI.cmake b/Modules/FindMPI.cmake
index 06ecfaa..48adf3c 100644
--- a/Modules/FindMPI.cmake
+++ b/Modules/FindMPI.cmake
@@ -102,7 +102,6 @@
# include this to handle the QUIETLY and REQUIRED arguments
include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
-include(${CMAKE_CURRENT_LIST_DIR}/GetPrerequisites.cmake)
#
# This part detects MPI compilers, attempting to wade through the mess of compiler names in
@@ -578,14 +577,13 @@ foreach (lang C CXX Fortran)
if (CMAKE_${lang}_COMPILER_WORKS)
# If the user supplies a compiler *name* instead of an absolute path, assume that we need to find THAT compiler.
if (MPI_${lang}_COMPILER)
- is_file_executable(MPI_${lang}_COMPILER MPI_COMPILER_IS_EXECUTABLE)
- if (NOT MPI_COMPILER_IS_EXECUTABLE)
+ if (NOT IS_ABSOLUTE "${MPI_${lang}_COMPILER}")
# Get rid of our default list of names and just search for the name the user wants.
set(_MPI_${lang}_COMPILER_NAMES ${MPI_${lang}_COMPILER})
set(MPI_${lang}_COMPILER "MPI_${lang}_COMPILER-NOTFOUND" CACHE FILEPATH "Cleared" FORCE)
- # If the user specifies a compiler, we don't want to try to search libraries either.
- set(try_libs FALSE)
endif()
+ # If the user specifies a compiler, we don't want to try to search libraries either.
+ set(try_libs FALSE)
else()
set(try_libs TRUE)
endif()
diff --git a/Modules/FindOpenSSL.cmake b/Modules/FindOpenSSL.cmake
index 3adc269..434ef58 100644
--- a/Modules/FindOpenSSL.cmake
+++ b/Modules/FindOpenSSL.cmake
@@ -2,26 +2,40 @@
# FindOpenSSL
# -----------
#
-# Try to find the OpenSSL encryption library
+# Find the OpenSSL encryption library.
#
-# Once done this will define
+# Imported Targets
+# ^^^^^^^^^^^^^^^^
#
-# ::
+# This module defines the following :prop_tgt:`IMPORTED` targets:
#
-# OPENSSL_ROOT_DIR - Set this variable to the root installation of OpenSSL
+# ``OpenSSL::SSL``
+# The OpenSSL ``ssl`` library, if found.
+# ``OpenSSL::Crypto``
+# The OpenSSL ``crypto`` library, if found.
#
+# Result Variables
+# ^^^^^^^^^^^^^^^^
#
+# This module will set the following variables in your project:
#
-# Read-Only variables:
+# ``OPENSSL_FOUND``
+# System has the OpenSSL library.
+# ``OPENSSL_INCLUDE_DIR``
+# The OpenSSL include directory.
+# ``OPENSSL_CRYPTO_LIBRARY``
+# The OpenSSL crypto library.
+# ``OPENSSL_SSL_LIBRARY``
+# The OpenSSL SSL library.
+# ``OPENSSL_LIBRARIES``
+# All OpenSSL libraries.
+# ``OPENSSL_VERSION``
+# This is set to ``$major.$minor.$revision$patch`` (e.g. ``0.9.8s``).
#
-# ::
+# Hints
+# ^^^^^
#
-# OPENSSL_FOUND - System has the OpenSSL library
-# OPENSSL_INCLUDE_DIR - The OpenSSL include directory
-# OPENSSL_CRYPTO_LIBRARY - The OpenSSL crypto library
-# OPENSSL_SSL_LIBRARY - The OpenSSL SSL library
-# OPENSSL_LIBRARIES - All OpenSSL libraries
-# OPENSSL_VERSION - This is set to $major.$minor.$revision$patch (eg. 0.9.8s)
+# Set ``OPENSSL_ROOT_DIR`` to the root directory of an OpenSSL installation.
#=============================================================================
# Copyright 2006-2009 Kitware, Inc.
@@ -99,15 +113,20 @@ if(WIN32 AND NOT CYGWIN)
# We are using the libraries located in the VC subdir instead of the parent directory eventhough :
# libeay32MD.lib is identical to ../libeay32.lib, and
# ssleay32MD.lib is identical to ../ssleay32.lib
+
+ set(_OPENSSL_PATH_SUFFIXES
+ "lib"
+ "VC"
+ "lib/VC"
+ )
+
find_library(LIB_EAY_DEBUG
NAMES
libeay32MDd
libeay32d
${_OPENSSL_ROOT_HINTS_AND_PATHS}
PATH_SUFFIXES
- "lib"
- "VC"
- "lib/VC"
+ ${_OPENSSL_PATH_SUFFIXES}
)
find_library(LIB_EAY_RELEASE
@@ -116,9 +135,7 @@ if(WIN32 AND NOT CYGWIN)
libeay32
${_OPENSSL_ROOT_HINTS_AND_PATHS}
PATH_SUFFIXES
- "lib"
- "VC"
- "lib/VC"
+ ${_OPENSSL_PATH_SUFFIXES}
)
find_library(SSL_EAY_DEBUG
@@ -127,9 +144,7 @@ if(WIN32 AND NOT CYGWIN)
ssleay32d
${_OPENSSL_ROOT_HINTS_AND_PATHS}
PATH_SUFFIXES
- "lib"
- "VC"
- "lib/VC"
+ ${_OPENSSL_PATH_SUFFIXES}
)
find_library(SSL_EAY_RELEASE
@@ -139,9 +154,7 @@ if(WIN32 AND NOT CYGWIN)
ssl
${_OPENSSL_ROOT_HINTS_AND_PATHS}
PATH_SUFFIXES
- "lib"
- "VC"
- "lib/VC"
+ ${_OPENSSL_PATH_SUFFIXES}
)
set(LIB_EAY_LIBRARY_DEBUG "${LIB_EAY_DEBUG}")
@@ -155,9 +168,9 @@ if(WIN32 AND NOT CYGWIN)
mark_as_advanced(LIB_EAY_LIBRARY_DEBUG LIB_EAY_LIBRARY_RELEASE
SSL_EAY_LIBRARY_DEBUG SSL_EAY_LIBRARY_RELEASE)
- set( OPENSSL_SSL_LIBRARY ${SSL_EAY_LIBRARY} )
- set( OPENSSL_CRYPTO_LIBRARY ${LIB_EAY_LIBRARY} )
- set( OPENSSL_LIBRARIES ${SSL_EAY_LIBRARY} ${LIB_EAY_LIBRARY} )
+ set(OPENSSL_SSL_LIBRARY ${SSL_EAY_LIBRARY} )
+ set(OPENSSL_CRYPTO_LIBRARY ${LIB_EAY_LIBRARY} )
+ set(OPENSSL_LIBRARIES ${SSL_EAY_LIBRARY} ${LIB_EAY_LIBRARY} )
elseif(MINGW)
# same player, for MinGW
set(LIB_EAY_NAMES libeay32)
@@ -185,9 +198,9 @@ if(WIN32 AND NOT CYGWIN)
)
mark_as_advanced(SSL_EAY LIB_EAY)
- set( OPENSSL_SSL_LIBRARY ${SSL_EAY} )
- set( OPENSSL_CRYPTO_LIBRARY ${LIB_EAY} )
- set( OPENSSL_LIBRARIES ${SSL_EAY} ${LIB_EAY} )
+ set(OPENSSL_SSL_LIBRARY ${SSL_EAY} )
+ set(OPENSSL_CRYPTO_LIBRARY ${LIB_EAY} )
+ set(OPENSSL_LIBRARIES ${SSL_EAY} ${LIB_EAY} )
unset(LIB_EAY_NAMES)
unset(SSL_EAY_NAMES)
else()
@@ -213,9 +226,9 @@ if(WIN32 AND NOT CYGWIN)
)
mark_as_advanced(SSL_EAY LIB_EAY)
- set( OPENSSL_SSL_LIBRARY ${SSL_EAY} )
- set( OPENSSL_CRYPTO_LIBRARY ${LIB_EAY} )
- set( OPENSSL_LIBRARIES ${SSL_EAY} ${LIB_EAY} )
+ set(OPENSSL_SSL_LIBRARY ${SSL_EAY} )
+ set(OPENSSL_CRYPTO_LIBRARY ${LIB_EAY} )
+ set(OPENSSL_LIBRARIES ${SSL_EAY} ${LIB_EAY} )
endif()
else()
@@ -338,3 +351,66 @@ else ()
endif ()
mark_as_advanced(OPENSSL_INCLUDE_DIR OPENSSL_LIBRARIES)
+
+if(OPENSSL_FOUND)
+ if(NOT TARGET OpenSSL::Crypto AND
+ (EXISTS "${OPENSSL_CRYPTO_LIBRARY}" OR
+ EXISTS "${LIB_EAY_LIBRARY_DEBUG}" OR
+ EXISTS "${LIB_EAY_LIBRARY_RELEASE}")
+ )
+ add_library(OpenSSL::Crypto UNKNOWN IMPORTED)
+ set_target_properties(OpenSSL::Crypto PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${OPENSSL_INCLUDE_DIR}")
+ if(EXISTS "${OPENSSL_CRYPTO_LIBRARY}")
+ set_target_properties(OpenSSL::Crypto PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES "C"
+ IMPORTED_LOCATION "${OPENSSL_CRYPTO_LIBRARY}")
+ endif()
+ if(EXISTS "${LIB_EAY_LIBRARY_DEBUG}")
+ set_property(TARGET OpenSSL::Crypto APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS DEBUG)
+ set_target_properties(OpenSSL::Crypto PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "C"
+ IMPORTED_LOCATION_DEBUG "${LIB_EAY_LIBRARY_DEBUG}")
+ endif()
+ if(EXISTS "${LIB_EAY_LIBRARY_RELEASE}")
+ set_property(TARGET OpenSSL::Crypto APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS RELEASE)
+ set_target_properties(OpenSSL::Crypto PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "C"
+ IMPORTED_LOCATION_RELEASE "${LIB_EAY_LIBRARY_RELEASE}")
+ endif()
+ endif()
+ if(NOT TARGET OpenSSL::SSL AND
+ (EXISTS "${OPENSSL_SSL_LIBRARY}" OR
+ EXISTS "${SSL_EAY_LIBRARY_DEBUG}" OR
+ EXISTS "${SSL_EAY_LIBRARY_RELEASE}")
+ )
+ add_library(OpenSSL::SSL UNKNOWN IMPORTED)
+ set_target_properties(OpenSSL::SSL PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${OPENSSL_INCLUDE_DIR}")
+ if(EXISTS "${OPENSSL_SSL_LIBRARY}")
+ set_target_properties(OpenSSL::SSL PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES "C"
+ IMPORTED_LOCATION "${OPENSSL_SSL_LIBRARY}")
+ endif()
+ if(EXISTS "${SSL_EAY_LIBRARY_DEBUG}")
+ set_property(TARGET OpenSSL::SSL APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS DEBUG)
+ set_target_properties(OpenSSL::SSL PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "C"
+ IMPORTED_LOCATION_DEBUG "${SSL_EAY_LIBRARY_DEBUG}")
+ endif()
+ if(EXISTS "${SSL_EAY_LIBRARY_RELEASE}")
+ set_property(TARGET OpenSSL::SSL APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS RELEASE)
+ set_target_properties(OpenSSL::SSL PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "C"
+ IMPORTED_LOCATION_RELEASE "${SSL_EAY_LIBRARY_RELEASE}")
+ endif()
+ if(TARGET OpenSSL::Crypto)
+ set_target_properties(OpenSSL::SSL PROPERTIES
+ INTERFACE_LINK_LIBRARIES OpenSSL::Crypto)
+ endif()
+ endif()
+endif()
diff --git a/Modules/FindPkgConfig.cmake b/Modules/FindPkgConfig.cmake
index 53c17f1..ae6903e 100644
--- a/Modules/FindPkgConfig.cmake
+++ b/Modules/FindPkgConfig.cmake
@@ -109,7 +109,7 @@ macro(_pkgconfig_parse_options _result _is_req _is_silent _no_cmake_path _no_cma
set(${_no_cmake_path} 1)
set(${_no_cmake_environment_path} 1)
endif()
- elseif(${CMAKE_MINIMUM_REQUIRED_VERSION} VERSION_LESS 3.1)
+ elseif(CMAKE_MINIMUM_REQUIRED_VERSION VERSION_LESS 3.1)
set(${_no_cmake_path} 1)
set(${_no_cmake_environment_path} 1)
endif()
@@ -192,9 +192,9 @@ macro(_pkg_check_modules_internal _is_required _is_silent _no_cmake_path _no_cma
# give out status message telling checked module
if (NOT ${_is_silent})
if (_pkg_check_modules_cnt EQUAL 1)
- message(STATUS "checking for module '${_pkg_check_modules_list}'")
+ message(STATUS "Checking for module '${_pkg_check_modules_list}'")
else()
- message(STATUS "checking for modules '${_pkg_check_modules_list}'")
+ message(STATUS "Checking for modules '${_pkg_check_modules_list}'")
endif()
endif()
@@ -327,7 +327,7 @@ macro(_pkg_check_modules_internal _is_required _is_silent _no_cmake_path _no_cma
# evaluate result and tell failures
if (_pkgconfig_retval)
if(NOT ${_is_silent})
- message(STATUS " package '${_pkg_check_modules_pkg}' not found")
+ message(STATUS " Package '${_pkg_check_modules_pkg}' not found")
endif()
set(_pkg_check_modules_failed 1)
@@ -361,7 +361,7 @@ macro(_pkg_check_modules_internal _is_required _is_silent _no_cmake_path _no_cma
_pkgconfig_invoke(${_pkg_check_modules_pkg} "${_pkg_check_prefix}" LIBDIR "" --variable=libdir )
if (NOT ${_is_silent})
- message(STATUS " found ${_pkg_check_modules_pkg}, version ${_pkgconfig_VERSION}")
+ message(STATUS " Found ${_pkg_check_modules_pkg}, version ${_pkgconfig_VERSION}")
endif ()
endforeach()
@@ -529,7 +529,7 @@ macro(pkg_search_module _prefix _module0)
_pkgconfig_parse_options(_pkg_modules_alt _pkg_is_required _pkg_is_silent _no_cmake_path _no_cmake_environment_path "${_module0}" ${ARGN})
if (NOT ${_pkg_is_silent})
- message(STATUS "checking for one of the modules '${_pkg_modules_alt}'")
+ message(STATUS "Checking for one of the modules '${_pkg_modules_alt}'")
endif ()
# iterate through all modules and stop at the first working one.
diff --git a/Modules/FindProtobuf.cmake b/Modules/FindProtobuf.cmake
index f01bd41..335c408 100644
--- a/Modules/FindProtobuf.cmake
+++ b/Modules/FindProtobuf.cmake
@@ -9,8 +9,9 @@
# ``PROTOBUF_SRC_ROOT_FOLDER``
# When compiling with MSVC, if this cache variable is set
# the protobuf-default VS project build locations
-# (vsprojects/Debug & vsprojects/Release) will be searched
-# for libraries and binaries.
+# (vsprojects/Debug and vsprojects/Release
+# or vsprojects/x64/Debug and vsprojects/x64/Release)
+# will be searched for libraries and binaries.
# ``PROTOBUF_IMPORT_DIRS``
# List of additional directories to be searched for
# imported .proto files.
@@ -146,18 +147,22 @@ function(PROTOBUF_GENERATE_CPP SRCS HDRS)
set(${HDRS} ${${HDRS}} PARENT_SCOPE)
endfunction()
+if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+ set(_PROTOBUF_ARCH_DIR x64/)
+endif()
+
# Internal function: search for normal library as well as a debug one
# if the debug one is specified also include debug/optimized keywords
# in *_LIBRARIES variable
function(_protobuf_find_libraries name filename)
find_library(${name}_LIBRARY
NAMES ${filename}
- PATHS ${PROTOBUF_SRC_ROOT_FOLDER}/vsprojects/Release)
+ PATHS ${PROTOBUF_SRC_ROOT_FOLDER}/vsprojects/${_PROTOBUF_ARCH_DIR}Release)
mark_as_advanced(${name}_LIBRARY)
find_library(${name}_LIBRARY_DEBUG
NAMES ${filename}
- PATHS ${PROTOBUF_SRC_ROOT_FOLDER}/vsprojects/Debug)
+ PATHS ${PROTOBUF_SRC_ROOT_FOLDER}/vsprojects/${_PROTOBUF_ARCH_DIR}Debug)
mark_as_advanced(${name}_LIBRARY_DEBUG)
if(NOT ${name}_LIBRARY_DEBUG)
@@ -234,8 +239,8 @@ find_program(PROTOBUF_PROTOC_EXECUTABLE
NAMES protoc
DOC "The Google Protocol Buffers Compiler"
PATHS
- ${PROTOBUF_SRC_ROOT_FOLDER}/vsprojects/Release
- ${PROTOBUF_SRC_ROOT_FOLDER}/vsprojects/Debug
+ ${PROTOBUF_SRC_ROOT_FOLDER}/vsprojects/${_PROTOBUF_ARCH_DIR}Release
+ ${PROTOBUF_SRC_ROOT_FOLDER}/vsprojects/${_PROTOBUF_ARCH_DIR}Debug
)
mark_as_advanced(PROTOBUF_PROTOC_EXECUTABLE)
diff --git a/Modules/FindTIFF.cmake b/Modules/FindTIFF.cmake
index a67d24d..ed092ea 100644
--- a/Modules/FindTIFF.cmake
+++ b/Modules/FindTIFF.cmake
@@ -34,7 +34,19 @@
find_path(TIFF_INCLUDE_DIR tiff.h)
set(TIFF_NAMES ${TIFF_NAMES} tiff libtiff tiff3 libtiff3)
-find_library(TIFF_LIBRARY NAMES ${TIFF_NAMES} )
+foreach(name ${TIFF_NAMES})
+ list(APPEND TIFF_NAMES_DEBUG "${name}d")
+endforeach()
+
+if(NOT TIFF_LIBRARY)
+ find_library(TIFF_LIBRARY_RELEASE NAMES ${TIFF_NAMES})
+ find_library(TIFF_LIBRARY_DEBUG NAMES ${TIFF_NAMES_DEBUG})
+ include(${CMAKE_CURRENT_LIST_DIR}/SelectLibraryConfigurations.cmake)
+ select_library_configurations(TIFF)
+ mark_as_advanced(TIFF_LIBRARY_RELEASE TIFF_LIBRARY_DEBUG)
+endif()
+unset(TIFF_NAMES)
+unset(TIFF_NAMES_DEBUG)
if(TIFF_INCLUDE_DIR AND EXISTS "${TIFF_INCLUDE_DIR}/tiffvers.h")
file(STRINGS "${TIFF_INCLUDE_DIR}/tiffvers.h" tiff_version_str
diff --git a/Modules/FindXercesC.cmake b/Modules/FindXercesC.cmake
index fd0b992..cf84826 100644
--- a/Modules/FindXercesC.cmake
+++ b/Modules/FindXercesC.cmake
@@ -61,10 +61,18 @@ find_path(XercesC_INCLUDE_DIR
DOC "Xerces-C++ include directory")
mark_as_advanced(XercesC_INCLUDE_DIR)
-# Find all XercesC libraries
-find_library(XercesC_LIBRARY NAMES "xerces-c" "xerces-c_3" "xerces-c_2"
- DOC "Xerces-C++ libraries")
-mark_as_advanced(XercesC_LIBRARY)
+if(NOT XercesC_LIBRARY)
+ # Find all XercesC libraries
+ find_library(XercesC_LIBRARY_RELEASE
+ NAMES "xerces-c" "xerces-c_3"
+ DOC "Xerces-C++ libraries (release)")
+ find_library(XercesC_LIBRARY_DEBUG
+ NAMES "xerces-cd" "xerces-c_3D" "xerces-c_3_1D"
+ DOC "Xerces-C++ libraries (debug)")
+ include(${CMAKE_CURRENT_LIST_DIR}/SelectLibraryConfigurations.cmake)
+ select_library_configurations(XercesC)
+ mark_as_advanced(XercesC_LIBRARY_RELEASE XercesC_LIBRARY_DEBUG)
+endif()
if(XercesC_INCLUDE_DIR)
_XercesC_GET_VERSION("${XercesC_INCLUDE_DIR}/xercesc/util/XercesVersion.hpp")
diff --git a/Modules/GetPrerequisites.cmake b/Modules/GetPrerequisites.cmake
index 23d486e..e4018b6 100644
--- a/Modules/GetPrerequisites.cmake
+++ b/Modules/GetPrerequisites.cmake
@@ -229,9 +229,14 @@ function(is_file_executable file result_var)
if(file_cmd)
execute_process(COMMAND "${file_cmd}" "${file_full}"
+ RESULT_VARIABLE file_rv
OUTPUT_VARIABLE file_ov
+ ERROR_VARIABLE file_ev
OUTPUT_STRIP_TRAILING_WHITESPACE
)
+ if(NOT file_rv STREQUAL "0")
+ message(FATAL_ERROR "${file_cmd} failed: ${file_rv}\n${file_ev}")
+ endif()
# Replace the name of the file in the output with a placeholder token
# (the string " _file_full_ ") so that just in case the path name of
@@ -543,11 +548,21 @@ function(gp_resolved_file_type original_file file exepath dirs type_var)
if(CYGPATH_EXECUTABLE)
execute_process(COMMAND ${CYGPATH_EXECUTABLE} -W
+ RESULT_VARIABLE env_rv
OUTPUT_VARIABLE env_windir
+ ERROR_VARIABLE env_ev
OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if(NOT env_rv STREQUAL "0")
+ message(FATAL_ERROR "${CYGPATH_EXECUTABLE} -W failed: ${env_rv}\n${env_ev}")
+ endif()
execute_process(COMMAND ${CYGPATH_EXECUTABLE} -S
+ RESULT_VARIABLE env_rv
OUTPUT_VARIABLE env_sysdir
+ ERROR_VARIABLE env_ev
OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if(NOT env_rv STREQUAL "0")
+ message(FATAL_ERROR "${CYGPATH_EXECUTABLE} -S failed: ${env_rv}\n${env_ev}")
+ endif()
string(TOLOWER "${env_windir}" windir)
string(TOLOWER "${env_sysdir}" sysroot)
@@ -685,6 +700,8 @@ function(get_prerequisites target prerequisites_var exclude_system recurse exepa
return()
endif()
+ set(gp_cmd_maybe_filter) # optional command to pre-filter gp_tool results
+
if(gp_tool STREQUAL "ldd")
set(gp_cmd_args "")
set(gp_regex "^[\t ]*[^\t ]+ => ([^\t\(]+) .*${eol_char}$")
@@ -709,6 +726,11 @@ function(get_prerequisites target prerequisites_var exclude_system recurse exepa
set(gp_regex_error "")
set(gp_regex_fallback "")
set(gp_regex_cmp_count 1)
+ # objdump generaates copious output so we create a grep filter to pre-filter results
+ find_program(gp_grep_cmd grep)
+ if(gp_grep_cmd)
+ set(gp_cmd_maybe_filter COMMAND ${gp_grep_cmd} "^[[:blank:]]*DLL Name: ")
+ endif()
else()
message(STATUS "warning: gp_tool='${gp_tool}' is an unknown tool...")
message(STATUS "CMake function get_prerequisites needs more code to handle '${gp_tool}'")
@@ -765,8 +787,19 @@ function(get_prerequisites target prerequisites_var exclude_system recurse exepa
#
execute_process(
COMMAND ${gp_cmd} ${gp_cmd_args} ${target}
+ ${gp_cmd_maybe_filter}
+ RESULT_VARIABLE gp_rv
OUTPUT_VARIABLE gp_cmd_ov
+ ERROR_VARIABLE gp_ev
)
+ if(NOT gp_rv STREQUAL "0")
+ if(gp_tool STREQUAL "dumpbin")
+ # dumpbin error messages seem to go to stdout
+ message(FATAL_ERROR "${gp_cmd} failed: ${gp_rv}\n${gp_ev}\n${gp_cmd_ov}")
+ else()
+ message(FATAL_ERROR "${gp_cmd} failed: ${gp_rv}\n${gp_ev}")
+ endif()
+ endif()
if(gp_tool STREQUAL "ldd")
set(ENV{LD_LIBRARY_PATH} "${old_ld_env}")
@@ -791,8 +824,13 @@ function(get_prerequisites target prerequisites_var exclude_system recurse exepa
if(gp_tool STREQUAL "otool")
execute_process(
COMMAND otool -D ${target}
+ RESULT_VARIABLE otool_rv
OUTPUT_VARIABLE gp_install_id_ov
+ ERROR_VARIABLE otool_ev
)
+ if(NOT otool_rv STREQUAL "0")
+ message(FATAL_ERROR "otool -D failed: ${otool_rv}\n${otool_ev}")
+ endif()
# second line is install name
string(REGEX REPLACE ".*:\n" "" gp_install_id "${gp_install_id_ov}")
if(gp_install_id)
diff --git a/Modules/Platform/ARTOS-GNU-C.cmake b/Modules/Platform/ARTOS-GNU-C.cmake
new file mode 100644
index 0000000..967d0e7
--- /dev/null
+++ b/Modules/Platform/ARTOS-GNU-C.cmake
@@ -0,0 +1,9 @@
+# Define ARTOS to select proper behaviour and tell preprocessor to accept C++ style comments.
+set(CMAKE_C_FLAGS_INIT "-DARTOS -Xp -+")
+# ac doesn't support -g properly and doesn't support the normal gcc optimization options. Just use the defaults set by ac.
+set(CMAKE_C_FLAGS_DEBUG_INIT "")
+set(CMAKE_C_FLAGS_MINSIZEREL_INIT "-DNDEBUG")
+set(CMAKE_C_FLAGS_RELEASE_INIT "-DNDEBUG")
+set(CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "-DNDEBUG")
+# Most projects expect the stdio functions to be available.
+set(CMAKE_C_STANDARD_LIBRARIES_INIT "stdio.a")
diff --git a/Modules/Platform/ARTOS.cmake b/Modules/Platform/ARTOS.cmake
new file mode 100644
index 0000000..f9365d6
--- /dev/null
+++ b/Modules/Platform/ARTOS.cmake
@@ -0,0 +1,17 @@
+# Support for ARTOS RTOS (locamation.com)
+set(CMAKE_LINK_LIBRARY_SUFFIX "")
+set(CMAKE_STATIC_LIBRARY_PREFIX "")
+set(CMAKE_STATIC_LIBRARY_SUFFIX ".a")
+set(CMAKE_SHARED_LIBRARY_PREFIX "")
+set(CMAKE_SHARED_LIBRARY_SUFFIX ".a")
+set(CMAKE_EXECUTABLE_SUFFIX ".x")
+set(CMAKE_DL_LIBS "")
+
+set(CMAKE_FIND_LIBRARY_PREFIXES "")
+set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
+
+# ARTOS does not support shared libs
+set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS FALSE)
+
+set(CMAKE_C_LINK_SHARED_LIBRARY )
+set(CMAKE_C_LINK_MODULE_LIBRARY )
diff --git a/Modules/Platform/HP-UX.cmake b/Modules/Platform/HP-UX.cmake
index 65cc731..581301b 100644
--- a/Modules/Platform/HP-UX.cmake
+++ b/Modules/Platform/HP-UX.cmake
@@ -33,18 +33,11 @@ list(APPEND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES
# Initialize C and CXX link type selection flags. These flags are
# used when building a shared library, shared module, or executable
# that links to other libraries to select whether to use the static or
-# shared versions of the libraries. Note that C modules and shared
-# libs are built using ld directly so we leave off the "-Wl," portion.
-foreach(type SHARED_LIBRARY SHARED_MODULE)
- set(CMAKE_${type}_LINK_STATIC_C_FLAGS "-a archive")
- set(CMAKE_${type}_LINK_DYNAMIC_C_FLAGS "-a default")
-endforeach()
-foreach(type EXE)
- set(CMAKE_${type}_LINK_STATIC_C_FLAGS "-Wl,-a,archive")
- set(CMAKE_${type}_LINK_DYNAMIC_C_FLAGS "-Wl,-a,default")
-endforeach()
+# shared versions of the libraries.
foreach(type SHARED_LIBRARY SHARED_MODULE EXE)
- set(CMAKE_${type}_LINK_STATIC_CXX_FLAGS "-Wl,-a,archive")
- set(CMAKE_${type}_LINK_DYNAMIC_CXX_FLAGS "-Wl,-a,default")
+ foreach(lang C CXX)
+ set(CMAKE_${type}_LINK_STATIC_${lang}_FLAGS "-Wl,-a,archive")
+ set(CMAKE_${type}_LINK_DYNAMIC_${lang}_FLAGS "-Wl,-a,default")
+ endforeach()
endforeach()
diff --git a/Modules/Platform/SunOS.cmake b/Modules/Platform/SunOS.cmake
index aaa79c4..77946f2 100644
--- a/Modules/Platform/SunOS.cmake
+++ b/Modules/Platform/SunOS.cmake
@@ -7,14 +7,6 @@ if(CMAKE_SYSTEM MATCHES "SunOS-4")
set(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG_SEP ":")
endif()
-if(CMAKE_COMPILER_IS_GNUCXX)
- if(CMAKE_COMPILER_IS_GNUCC)
- set(CMAKE_CXX_CREATE_SHARED_LIBRARY
- "<CMAKE_C_COMPILER> <CMAKE_SHARED_LIBRARY_CXX_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS> <SONAME_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>")
- else()
- # Take default rule from CMakeDefaultMakeRuleVariables.cmake.
- endif()
-endif()
include(Platform/UnixPaths)
# Add the compiler's implicit link directories.
diff --git a/Modules/UseJava.cmake b/Modules/UseJava.cmake
index 5eb0ca8..c61591d 100644
--- a/Modules/UseJava.cmake
+++ b/Modules/UseJava.cmake
@@ -21,7 +21,8 @@
#
# This command creates a <target_name>.jar. It compiles the given
# source files (source) and adds the given resource files (resource) to
-# the jar file. If only resource files are given then just a jar file
+# the jar file. Source files can be java files or listing files
+# (prefixed by '@'). If only resource files are given then just a jar file
# is created. The list of include jars are added to the classpath when
# compiling the java sources and also to the dependencies of the target.
# INCLUDE_JARS also accepts other target names created by add_jar. For
@@ -210,14 +211,16 @@
#
# ::
#
-# install_jar(TARGET_NAME DESTINATION)
+# install_jar(target_name destination)
+# install_jar(target_name DESTINATION destination [COMPONENT component])
#
# This command installs the TARGET_NAME files to the given DESTINATION.
# It should be called in the same scope as add_jar() or it will fail.
#
# ::
#
-# install_jni_symlink(TARGET_NAME DESTINATION)
+# install_jni_symlink(target_name destination)
+# install_jni_symlink(target_name DESTINATION destination [COMPONENT component])
#
# This command installs the TARGET_NAME JNI symlinks to the given
# DESTINATION. It should be called in the same scope as add_jar() or it
@@ -423,6 +426,7 @@ function(add_jar _TARGET_NAME)
set(_JAVA_CLASS_FILES)
set(_JAVA_COMPILE_FILES)
+ set(_JAVA_COMPILE_FILELISTS)
set(_JAVA_DEPENDS)
set(_JAVA_COMPILE_DEPENDS)
set(_JAVA_RESOURCE_FILES)
@@ -433,7 +437,11 @@ function(add_jar _TARGET_NAME)
get_filename_component(_JAVA_PATH ${_JAVA_SOURCE_FILE} PATH)
get_filename_component(_JAVA_FULL ${_JAVA_SOURCE_FILE} ABSOLUTE)
- if (_JAVA_EXT MATCHES ".java")
+ if (_JAVA_SOURCE_FILE MATCHES "^@(.+)$")
+ get_filename_component(_JAVA_FULL ${CMAKE_MATCH_1} ABSOLUTE)
+ list(APPEND _JAVA_COMPILE_FILELISTS ${_JAVA_FULL})
+
+ elseif (_JAVA_EXT MATCHES ".java")
file(RELATIVE_PATH _JAVA_REL_BINARY_PATH ${_add_jar_OUTPUT_DIR} ${_JAVA_FULL})
file(RELATIVE_PATH _JAVA_REL_SOURCE_PATH ${CMAKE_CURRENT_SOURCE_DIR} ${_JAVA_FULL})
string(LENGTH ${_JAVA_REL_BINARY_PATH} _BIN_LEN)
@@ -492,11 +500,21 @@ function(add_jar _TARGET_NAME)
file(WRITE ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist "")
endif()
- if (_JAVA_COMPILE_FILES)
- # Create the list of files to compile.
- set(_JAVA_SOURCES_FILE ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_sources)
- string(REPLACE ";" "\"\n\"" _JAVA_COMPILE_STRING "\"${_JAVA_COMPILE_FILES}\"")
- file(WRITE ${_JAVA_SOURCES_FILE} ${_JAVA_COMPILE_STRING})
+ if (_JAVA_COMPILE_FILES OR _JAVA_COMPILE_FILELISTS)
+ set (_JAVA_SOURCES_FILELISTS)
+
+ if (_JAVA_COMPILE_FILES)
+ # Create the list of files to compile.
+ set(_JAVA_SOURCES_FILE ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_sources)
+ string(REPLACE ";" "\"\n\"" _JAVA_COMPILE_STRING "\"${_JAVA_COMPILE_FILES}\"")
+ file(WRITE ${_JAVA_SOURCES_FILE} ${_JAVA_COMPILE_STRING})
+ list (APPEND _JAVA_SOURCES_FILELISTS "@${_JAVA_SOURCES_FILE}")
+ endif()
+ if (_JAVA_COMPILE_FILELISTS)
+ foreach (_JAVA_FILELIST IN LISTS _JAVA_COMPILE_FILELISTS)
+ list (APPEND _JAVA_SOURCES_FILELISTS "@${_JAVA_FILELIST}")
+ endforeach()
+ endif()
# Compile the java files and create a list of class files
add_custom_command(
@@ -506,9 +524,9 @@ function(add_jar _TARGET_NAME)
${CMAKE_JAVA_COMPILE_FLAGS}
-classpath "${CMAKE_JAVA_INCLUDE_PATH_FINAL}"
-d ${CMAKE_JAVA_CLASS_OUTPUT_PATH}
- @${_JAVA_SOURCES_FILE}
+ ${_JAVA_SOURCES_FILELISTS}
COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_compiled_${_TARGET_NAME}
- DEPENDS ${_JAVA_COMPILE_FILES} ${_JAVA_COMPILE_DEPENDS}
+ DEPENDS ${_JAVA_COMPILE_FILES} ${_JAVA_COMPILE_FILELISTS} ${_JAVA_COMPILE_DEPENDS}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "Building Java objects for ${_TARGET_NAME}.jar"
)
@@ -613,7 +631,26 @@ function(add_jar _TARGET_NAME)
endfunction()
-function(INSTALL_JAR _TARGET_NAME _DESTINATION)
+function(INSTALL_JAR _TARGET_NAME)
+ if (ARGC EQUAL 2)
+ set (_DESTINATION ${ARGV1})
+ else()
+ cmake_parse_arguments(_install_jar
+ ""
+ "DESTINATION;COMPONENT"
+ ""
+ ${ARGN})
+ if (_install_jar_DESTINATION)
+ set (_DESTINATION ${_install_jar_DESTINATION})
+ else()
+ message(SEND_ERROR "install_jar: ${_TARGET_NAME}: DESTINATION must be specified.")
+ endif()
+
+ if (_install_jar_COMPONENT)
+ set (_COMPONENT COMPONENT ${_install_jar_COMPONENT})
+ endif()
+ endif()
+
get_property(__FILES
TARGET
${_TARGET_NAME}
@@ -627,13 +664,33 @@ function(INSTALL_JAR _TARGET_NAME _DESTINATION)
${__FILES}
DESTINATION
${_DESTINATION}
+ ${_COMPONENT}
)
else ()
- message(SEND_ERROR "The target ${_TARGET_NAME} is not known in this scope.")
+ message(SEND_ERROR "install_jar: The target ${_TARGET_NAME} is not known in this scope.")
endif ()
endfunction()
-function(INSTALL_JNI_SYMLINK _TARGET_NAME _DESTINATION)
+function(INSTALL_JNI_SYMLINK _TARGET_NAME)
+ if (ARGC EQUAL 2)
+ set (_DESTINATION ${ARGV1})
+ else()
+ cmake_parse_arguments(_install_jni_symlink
+ ""
+ "DESTINATION;COMPONENT"
+ ""
+ ${ARGN})
+ if (_install_jni_symlink_DESTINATION)
+ set (_DESTINATION ${_install_jni_symlink_DESTINATION})
+ else()
+ message(SEND_ERROR "install_jni_symlink: ${_TARGET_NAME}: DESTINATION must be specified.")
+ endif()
+
+ if (_install_jni_symlink_COMPONENT)
+ set (_COMPONENT COMPONENT ${_install_jni_symlink_COMPONENT})
+ endif()
+ endif()
+
get_property(__SYMLINK
TARGET
${_TARGET_NAME}
@@ -647,9 +704,10 @@ function(INSTALL_JNI_SYMLINK _TARGET_NAME _DESTINATION)
${__SYMLINK}
DESTINATION
${_DESTINATION}
+ ${_COMPONENT}
)
else ()
- message(SEND_ERROR "The target ${_TARGET_NAME} is not known in this scope.")
+ message(SEND_ERROR "install_jni_symlink: The target ${_TARGET_NAME} is not known in this scope.")
endif ()
endfunction()
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index 92fee8a..428b364 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -288,6 +288,7 @@ set(SRCS
cmInstallDirectoryGenerator.h
cmInstallDirectoryGenerator.cxx
cmLinkedTree.h
+ cmLinkItem.h
cmListFileCache.cxx
cmListFileCache.h
cmListFileLexer.c
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index 612ab7e..f0a7cbd 100644
--- a/Source/CMakeVersion.cmake
+++ b/Source/CMakeVersion.cmake
@@ -1,5 +1,5 @@
# CMake version number components.
set(CMake_VERSION_MAJOR 3)
set(CMake_VERSION_MINOR 3)
-set(CMake_VERSION_PATCH 20150728)
+set(CMake_VERSION_PATCH 20150819)
#set(CMake_VERSION_RC 1)
diff --git a/Source/CTest/cmCTestCoverageHandler.cxx b/Source/CTest/cmCTestCoverageHandler.cxx
index 6369e17..65599e0 100644
--- a/Source/CTest/cmCTestCoverageHandler.cxx
+++ b/Source/CTest/cmCTestCoverageHandler.cxx
@@ -1474,7 +1474,12 @@ int cmCTestCoverageHandler::HandleLCovCoverage(
<< std::endl, this->Quiet);
std::vector<std::string> files;
- this->FindLCovFiles(files);
+ if (!this->FindLCovFiles(files))
+ {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Error while finding LCov files.\n");
+ return 0;
+ }
std::vector<std::string>::iterator it;
if (files.empty())
@@ -1745,18 +1750,28 @@ void cmCTestCoverageHandler::FindGCovFiles(std::vector<std::string>& files)
}
//----------------------------------------------------------------------------
-void cmCTestCoverageHandler::FindLCovFiles(std::vector<std::string>& files)
+bool cmCTestCoverageHandler::FindLCovFiles(std::vector<std::string>& files)
{
cmsys::Glob gl;
gl.RecurseOff(); // No need of recurse if -prof_dir${BUILD_DIR} flag is
// used while compiling.
gl.RecurseThroughSymlinksOff();
std::string prevBinaryDir;
- cmSystemTools::ChangeDirectory(
- this->CTest->GetCTestConfiguration("BuildDirectory"));
+ std::string buildDir = this->CTest->GetCTestConfiguration("BuildDirectory");
+ if (cmSystemTools::ChangeDirectory(buildDir))
+ {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Error changing directory to " << buildDir << std::endl);
+ return false;
+ }
// Run profmerge to merge all *.dyn files into dpi files
- cmSystemTools::RunSingleCommand("profmerge");
+ if (!cmSystemTools::RunSingleCommand("profmerge"))
+ {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Error while running profmerge.\n");
+ return false;
+ }
prevBinaryDir = cmSystemTools::GetCurrentWorkingDirectory().c_str();
@@ -1766,10 +1781,16 @@ void cmCTestCoverageHandler::FindLCovFiles(std::vector<std::string>& files)
daGlob += "/*.dpi";
cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
" looking for dpi files in: " << daGlob << std::endl, this->Quiet);
- gl.FindFiles(daGlob);
+ if (!gl.FindFiles(daGlob))
+ {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Error while finding files matching " << daGlob << std::endl);
+ return false;
+ }
files.insert(files.end(), gl.GetFiles().begin(), gl.GetFiles().end());
cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
"Now searching in: " << daGlob << std::endl, this->Quiet);
+ return true;
}
//----------------------------------------------------------------------
diff --git a/Source/CTest/cmCTestCoverageHandler.h b/Source/CTest/cmCTestCoverageHandler.h
index 2ca123a..7102d1e 100644
--- a/Source/CTest/cmCTestCoverageHandler.h
+++ b/Source/CTest/cmCTestCoverageHandler.h
@@ -75,7 +75,7 @@ private:
//! Handle coverage using Intel's LCov
int HandleLCovCoverage(cmCTestCoverageHandlerContainer* cont);
- void FindLCovFiles(std::vector<std::string>& files);
+ bool FindLCovFiles(std::vector<std::string>& files);
//! Handle coverage using xdebug php coverage
int HandlePHPCoverage(cmCTestCoverageHandlerContainer* cont);
diff --git a/Source/QtDialog/Info.plist.in b/Source/QtDialog/Info.plist.in
index b9c4af5..00a27c3 100644
--- a/Source/QtDialog/Info.plist.in
+++ b/Source/QtDialog/Info.plist.in
@@ -28,5 +28,7 @@
<string>public.app-category.developer-tools</string>
<key>NSHumanReadableCopyright</key>
<string>${MACOSX_BUNDLE_COPYRIGHT}</string>
+ <key>NSHighResolutionCapable</key>
+ <true/>
</dict>
</plist>
diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx
index f65bd29..b976469 100644
--- a/Source/cmCTest.cxx
+++ b/Source/cmCTest.cxx
@@ -1546,9 +1546,8 @@ void cmCTest::StartXML(cmXMLWriter& xml, bool append)
xml.Attribute("Append", "true");
}
xml.Attribute("CompilerName", this->GetCTestConfiguration("Compiler"));
-#ifdef _COMPILER_VERSION
- xml.Attribute("CompilerVersion", _COMPILER_VERSION);
-#endif
+ xml.Attribute("CompilerVersion",
+ this->GetCTestConfiguration("CompilerVersion"));
xml.Attribute("OSName", info.GetOSName());
xml.Attribute("Hostname", info.GetHostname());
xml.Attribute("OSRelease", info.GetOSRelease());
diff --git a/Source/cmCommonTargetGenerator.cxx b/Source/cmCommonTargetGenerator.cxx
index 2225fdc..4840e89 100644
--- a/Source/cmCommonTargetGenerator.cxx
+++ b/Source/cmCommonTargetGenerator.cxx
@@ -20,8 +20,12 @@
#include "cmSystemTools.h"
#include "cmTarget.h"
-cmCommonTargetGenerator::cmCommonTargetGenerator(cmGeneratorTarget* gt)
- : GeneratorTarget(gt)
+cmCommonTargetGenerator::cmCommonTargetGenerator(
+ cmOutputConverter::RelativeRoot wd,
+ cmGeneratorTarget* gt
+ )
+ : WorkingDirectory(wd)
+ , GeneratorTarget(gt)
, Target(gt->Target)
, Makefile(gt->Makefile)
, LocalGenerator(static_cast<cmLocalCommonGenerator*>(gt->LocalGenerator))
@@ -101,47 +105,47 @@ void cmCommonTargetGenerator::AddModuleDefinitionFlag(std::string& flags)
}
//----------------------------------------------------------------------------
-const char* cmCommonTargetGenerator::GetFortranModuleDirectory()
+std::string cmCommonTargetGenerator::ComputeFortranModuleDirectory() const
{
- // Compute the module directory.
- if(!this->FortranModuleDirectoryComputed)
+ std::string mod_dir;
+ const char* target_mod_dir =
+ this->Target->GetProperty("Fortran_MODULE_DIRECTORY");
+ const char* moddir_flag =
+ this->Makefile->GetDefinition("CMAKE_Fortran_MODDIR_FLAG");
+ if(target_mod_dir && moddir_flag)
{
- const char* target_mod_dir =
- this->Target->GetProperty("Fortran_MODULE_DIRECTORY");
- const char* moddir_flag =
- this->Makefile->GetDefinition("CMAKE_Fortran_MODDIR_FLAG");
- if(target_mod_dir && moddir_flag)
+ // Compute the full path to the module directory.
+ if(cmSystemTools::FileIsFullPath(target_mod_dir))
{
- // Compute the full path to the module directory.
- if(cmSystemTools::FileIsFullPath(target_mod_dir))
- {
- // Already a full path.
- this->FortranModuleDirectory = target_mod_dir;
- }
- else
- {
- // Interpret relative to the current output directory.
- this->FortranModuleDirectory =
- this->Makefile->GetCurrentBinaryDirectory();
- this->FortranModuleDirectory += "/";
- this->FortranModuleDirectory += target_mod_dir;
- }
-
- // Make sure the module output directory exists.
- cmSystemTools::MakeDirectory(this->FortranModuleDirectory.c_str());
+ // Already a full path.
+ mod_dir = target_mod_dir;
+ }
+ else
+ {
+ // Interpret relative to the current output directory.
+ mod_dir = this->Makefile->GetCurrentBinaryDirectory();
+ mod_dir += "/";
+ mod_dir += target_mod_dir;
}
- this->FortranModuleDirectoryComputed = true;
- }
- // Return the computed directory.
- if(this->FortranModuleDirectory.empty())
- {
- return 0;
+ // Make sure the module output directory exists.
+ cmSystemTools::MakeDirectory(mod_dir);
}
- else
+ return mod_dir;
+}
+
+//----------------------------------------------------------------------------
+std::string cmCommonTargetGenerator::GetFortranModuleDirectory()
+{
+ // Compute the module directory.
+ if(!this->FortranModuleDirectoryComputed)
{
- return this->FortranModuleDirectory.c_str();
+ this->FortranModuleDirectoryComputed = true;
+ this->FortranModuleDirectory = this->ComputeFortranModuleDirectory();
}
+
+ // Return the computed directory.
+ return this->FortranModuleDirectory;
}
//----------------------------------------------------------------------------
@@ -155,19 +159,24 @@ void cmCommonTargetGenerator::AddFortranFlags(std::string& flags)
}
// Add a module output directory flag if necessary.
- const char* mod_dir = this->GetFortranModuleDirectory();
- if(!mod_dir)
+ std::string mod_dir = this->GetFortranModuleDirectory();
+ if (!mod_dir.empty())
+ {
+ mod_dir = this->Convert(mod_dir,
+ this->WorkingDirectory,
+ cmLocalGenerator::SHELL);
+ }
+ else
{
- mod_dir = this->Makefile->GetDefinition("CMAKE_Fortran_MODDIR_DEFAULT");
+ mod_dir =
+ this->Makefile->GetSafeDefinition("CMAKE_Fortran_MODDIR_DEFAULT");
}
- if(mod_dir)
+ if (!mod_dir.empty())
{
const char* moddir_flag =
this->Makefile->GetRequiredDefinition("CMAKE_Fortran_MODDIR_FLAG");
std::string modflag = moddir_flag;
- modflag += this->Convert(mod_dir,
- cmLocalGenerator::START_OUTPUT,
- cmLocalGenerator::SHELL);
+ modflag += mod_dir;
this->LocalGenerator->AppendFlags(flags, modflag);
}
@@ -267,7 +276,8 @@ std::string cmCommonTargetGenerator::GetFrameworkFlags(std::string const& l)
std::string flags;
const char* cfg = this->LocalGenerator->GetConfigName().c_str();
- if(cmComputeLinkInformation* cli = this->Target->GetLinkInformation(cfg))
+ if(cmComputeLinkInformation* cli =
+ this->GeneratorTarget->GetLinkInformation(cfg))
{
std::vector<std::string> const& frameworks = cli->GetFrameworkPaths();
for(std::vector<std::string>::const_iterator i = frameworks.begin();
@@ -368,3 +378,37 @@ std::string cmCommonTargetGenerator::GetIncludes(std::string const& l)
}
return i->second;
}
+
+std::vector<std::string>
+cmCommonTargetGenerator::GetLinkedTargetDirectories() const
+{
+ std::vector<std::string> dirs;
+ std::set<cmTarget const*> emitted;
+ if (cmComputeLinkInformation* cli =
+ this->GeneratorTarget->GetLinkInformation(this->ConfigName))
+ {
+ cmComputeLinkInformation::ItemVector const& items = cli->GetItems();
+ for(cmComputeLinkInformation::ItemVector::const_iterator
+ i = items.begin(); i != items.end(); ++i)
+ {
+ cmTarget const* linkee = i->Target;
+ if(linkee && !linkee->IsImported()
+ // We can ignore the INTERFACE_LIBRARY items because
+ // Target->GetLinkInformation already processed their
+ // link interface and they don't have any output themselves.
+ && linkee->GetType() != cmTarget::INTERFACE_LIBRARY
+ && emitted.insert(linkee).second)
+ {
+ cmGeneratorTarget* gt =
+ this->GlobalGenerator->GetGeneratorTarget(linkee);
+ cmLocalGenerator* lg = gt->GetLocalGenerator();
+ cmMakefile* mf = linkee->GetMakefile();
+ std::string di = mf->GetCurrentBinaryDirectory();
+ di += "/";
+ di += lg->GetTargetDirectory(*linkee);
+ dirs.push_back(di);
+ }
+ }
+ }
+ return dirs;
+}
diff --git a/Source/cmCommonTargetGenerator.h b/Source/cmCommonTargetGenerator.h
index 5451a5a..0a49e12 100644
--- a/Source/cmCommonTargetGenerator.h
+++ b/Source/cmCommonTargetGenerator.h
@@ -29,7 +29,8 @@ class cmTarget;
class cmCommonTargetGenerator
{
public:
- cmCommonTargetGenerator(cmGeneratorTarget* gt);
+ cmCommonTargetGenerator(cmOutputConverter::RelativeRoot wd,
+ cmGeneratorTarget* gt);
virtual ~cmCommonTargetGenerator();
std::string const& GetConfigName() const;
@@ -46,6 +47,7 @@ protected:
// Helper to add flag for windows .def file.
void AddModuleDefinitionFlag(std::string& flags);
+ cmOutputConverter::RelativeRoot WorkingDirectory;
cmGeneratorTarget* GeneratorTarget;
cmTarget* Target;
cmMakefile* Makefile;
@@ -59,7 +61,8 @@ protected:
// Target-wide Fortran module output directory.
bool FortranModuleDirectoryComputed;
std::string FortranModuleDirectory;
- const char* GetFortranModuleDirectory();
+ std::string GetFortranModuleDirectory();
+ virtual std::string ComputeFortranModuleDirectory() const;
// Compute target-specific Fortran language flags.
void AddFortranFlags(std::string& flags);
@@ -85,6 +88,8 @@ protected:
ByLanguageMap DefinesByLanguage;
std::string GetIncludes(std::string const& l);
ByLanguageMap IncludesByLanguage;
+
+ std::vector<std::string> GetLinkedTargetDirectories() const;
};
#endif
diff --git a/Source/cmComputeLinkDepends.cxx b/Source/cmComputeLinkDepends.cxx
index abd9877..8ba8847 100644
--- a/Source/cmComputeLinkDepends.cxx
+++ b/Source/cmComputeLinkDepends.cxx
@@ -173,18 +173,19 @@ items that we know the linker will re-use automatically (shared libs).
//----------------------------------------------------------------------------
cmComputeLinkDepends
-::cmComputeLinkDepends(cmTarget const* target, const std::string& config)
+::cmComputeLinkDepends(const cmGeneratorTarget* target,
+ const std::string& config)
{
// Store context information.
this->Target = target;
- this->Makefile = this->Target->GetMakefile();
+ this->Makefile = this->Target->Target->GetMakefile();
this->GlobalGenerator = this->Makefile->GetGlobalGenerator();
this->CMakeInstance = this->GlobalGenerator->GetCMakeInstance();
// The configuration being linked.
this->HasConfig = !config.empty();
this->Config = (this->HasConfig)? config : std::string();
- this->LinkType = this->Target->ComputeLinkType(this->Config);
+ this->LinkType = this->Target->Target->ComputeLinkType(this->Config);
// Enable debug mode if requested.
this->DebugMode = this->Makefile->IsOn("CMAKE_LINK_DEPENDS_DEBUG_MODE");
@@ -363,7 +364,7 @@ void cmComputeLinkDepends::FollowLinkEntry(BFSEntry const& qe)
{
// Follow the target dependencies.
if(cmTarget::LinkInterface const* iface =
- entry.Target->GetLinkInterface(this->Config, this->Target))
+ entry.Target->GetLinkInterface(this->Config, this->Target->Target))
{
const bool isIface =
entry.Target->GetType() == cmTarget::INTERFACE_LIBRARY;
@@ -461,7 +462,7 @@ void cmComputeLinkDepends::HandleSharedDependency(SharedDepEntry const& dep)
if(entry.Target)
{
if(cmTarget::LinkInterface const* iface =
- entry.Target->GetLinkInterface(this->Config, this->Target))
+ entry.Target->GetLinkInterface(this->Config, this->Target->Target))
{
// Follow public and private dependencies transitively.
this->FollowSharedDeps(index, iface, true);
@@ -552,7 +553,7 @@ void cmComputeLinkDepends::AddDirectLinkEntries()
{
// Add direct link dependencies in this configuration.
cmTarget::LinkImplementation const* impl =
- this->Target->GetLinkImplementation(this->Config);
+ this->Target->Target->GetLinkImplementation(this->Config);
this->AddLinkEntries(-1, impl->Libraries);
for(std::vector<cmLinkItem>::const_iterator
wi = impl->WrongConfigLibraries.begin();
@@ -634,7 +635,7 @@ cmTarget const* cmComputeLinkDepends::FindTargetToLink(int depender_index,
const std::string& name)
{
// Look for a target in the scope of the depender.
- cmTarget const* from = this->Target;
+ cmTarget const* from = this->Target->Target;
if(depender_index >= 0)
{
if(cmTarget const* depender = this->EntryList[depender_index].Target)
@@ -932,7 +933,7 @@ int cmComputeLinkDepends::ComputeComponentCount(NodeList const& nl)
if(cmTarget const* target = this->EntryList[*ni].Target)
{
if(cmTarget::LinkInterface const* iface =
- target->GetLinkInterface(this->Config, this->Target))
+ target->GetLinkInterface(this->Config, this->Target->Target))
{
if(iface->Multiplicity > count)
{
diff --git a/Source/cmComputeLinkDepends.h b/Source/cmComputeLinkDepends.h
index 51a08c5..b925a4f 100644
--- a/Source/cmComputeLinkDepends.h
+++ b/Source/cmComputeLinkDepends.h
@@ -22,6 +22,7 @@
class cmComputeComponentGraph;
class cmGlobalGenerator;
class cmMakefile;
+class cmGeneratorTarget;
class cmTarget;
class cmake;
@@ -31,7 +32,8 @@ class cmake;
class cmComputeLinkDepends
{
public:
- cmComputeLinkDepends(cmTarget const* target, const std::string& config);
+ cmComputeLinkDepends(cmGeneratorTarget const* target,
+ const std::string& config);
~cmComputeLinkDepends();
// Basic information about each link item.
@@ -57,7 +59,7 @@ public:
private:
// Context information.
- cmTarget const* Target;
+ cmGeneratorTarget const* Target;
cmMakefile* Makefile;
cmGlobalGenerator const* GlobalGenerator;
cmake* CMakeInstance;
diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx
index e63b44f..6ba0eed 100644
--- a/Source/cmComputeLinkInformation.cxx
+++ b/Source/cmComputeLinkInformation.cxx
@@ -14,11 +14,13 @@
#include "cmComputeLinkDepends.h"
#include "cmOrderDirectories.h"
+#include "cmLocalGenerator.h"
#include "cmGlobalGenerator.h"
#include "cmState.h"
#include "cmOutputConverter.h"
#include "cmMakefile.h"
#include "cmTarget.h"
+#include "cmGeneratorTarget.h"
#include "cmake.h"
#include "cmAlgorithms.h"
@@ -241,12 +243,14 @@ because this need be done only for shared libraries without soname-s.
//----------------------------------------------------------------------------
cmComputeLinkInformation
-::cmComputeLinkInformation(cmTarget const* target, const std::string& config)
+::cmComputeLinkInformation(const cmGeneratorTarget* target,
+ const std::string& config)
{
// Store context information.
this->Target = target;
- this->Makefile = this->Target->GetMakefile();
- this->GlobalGenerator = this->Makefile->GetGlobalGenerator();
+ this->Makefile = this->Target->Target->GetMakefile();
+ this->GlobalGenerator =
+ this->Target->GetLocalGenerator()->GetGlobalGenerator();
this->CMakeInstance = this->GlobalGenerator->GetCMakeInstance();
// Check whether to recognize OpenBSD-style library versioned names.
@@ -280,14 +284,14 @@ cmComputeLinkInformation
// Check whether we should skip dependencies on shared library files.
this->LinkDependsNoShared =
- this->Target->GetPropertyAsBool("LINK_DEPENDS_NO_SHARED");
+ this->Target->Target->GetPropertyAsBool("LINK_DEPENDS_NO_SHARED");
// On platforms without import libraries there may be a special flag
// to use when creating a plugin (module) that obtains symbols from
// the program that will load it.
this->LoaderFlag = 0;
if(!this->UseImportLibrary &&
- this->Target->GetType() == cmTarget::MODULE_LIBRARY)
+ this->Target->Target->GetType() == cmTarget::MODULE_LIBRARY)
{
std::string loader_flag_var = "CMAKE_SHARED_MODULE_LOADER_";
loader_flag_var += this->LinkLanguage;
@@ -305,10 +309,10 @@ cmComputeLinkInformation
// Get options needed to specify RPATHs.
this->RuntimeUseChrpath = false;
- if(this->Target->GetType() != cmTarget::STATIC_LIBRARY)
+ if(this->Target->Target->GetType() != cmTarget::STATIC_LIBRARY)
{
const char* tType =
- ((this->Target->GetType() == cmTarget::EXECUTABLE)?
+ ((this->Target->Target->GetType() == cmTarget::EXECUTABLE)?
"EXECUTABLE" : "SHARED_LIBRARY");
std::string rtVar = "CMAKE_";
rtVar += tType;
@@ -321,6 +325,7 @@ cmComputeLinkInformation
this->RuntimeAlways =
(this->Makefile->
GetSafeDefinition("CMAKE_PLATFORM_REQUIRED_RUNTIME_PATH"));
+
this->RuntimeUseChrpath = this->Target->IsChrpathUsed(config);
// Get options needed to help find dependent libraries.
@@ -373,9 +378,9 @@ cmComputeLinkInformation
// Add the search path entries requested by the user to path ordering.
this->OrderLinkerSearchPath
- ->AddUserDirectories(this->Target->GetLinkDirectories());
+ ->AddUserDirectories(this->Target->Target->GetLinkDirectories());
this->OrderRuntimeSearchPath
- ->AddUserDirectories(this->Target->GetLinkDirectories());
+ ->AddUserDirectories(this->Target->Target->GetLinkDirectories());
// Set up the implicit link directories.
this->LoadImplicitLinkInfo();
@@ -403,12 +408,13 @@ cmComputeLinkInformation
// order to support such projects we need to add the directories
// containing libraries linked with a full path to the -L path.
this->OldLinkDirMode =
- this->Target->GetPolicyStatusCMP0003() != cmPolicies::NEW;
+ this->Target->Target->GetPolicyStatusCMP0003() != cmPolicies::NEW;
if(this->OldLinkDirMode)
{
// Construct a mask to not bother with this behavior for link
// directories already specified by the user.
- std::vector<std::string> const& dirs = this->Target->GetLinkDirectories();
+ std::vector<std::string> const& dirs =
+ this->Target->Target->GetLinkDirectories();
this->OldLinkDirMask.insert(dirs.begin(), dirs.end());
}
@@ -514,10 +520,12 @@ bool cmComputeLinkInformation::Compute()
// Restore the target link type so the correct system runtime
// libraries are found.
- const char* lss = this->Target->GetProperty("LINK_SEARCH_END_STATIC");
- if(cmSystemTools::IsOn(lss))
+ const char* lss =
+ this->Target->Target->GetProperty("LINK_SEARCH_END_STATIC");
+ if(lss)
{
- this->SetCurrentLinkType(LinkStatic);
+ this->SetCurrentLinkType(
+ cmSystemTools::IsOn(lss) ? LinkStatic : LinkShared);
}
else
{
@@ -535,9 +543,7 @@ bool cmComputeLinkInformation::Compute()
i != wrongItems.end(); ++i)
{
cmTarget const* tgt = *i;
- cmGeneratorTarget *gtgt = tgt->GetMakefile()
- ->GetGlobalGenerator()
- ->GetGeneratorTarget(tgt);
+ cmGeneratorTarget *gtgt = this->GlobalGenerator->GetGeneratorTarget(tgt);
bool implib =
(this->UseImportLibrary &&
(tgt->GetType() == cmTarget::SHARED_LIBRARY));
@@ -567,7 +573,7 @@ bool cmComputeLinkInformation::Compute()
"name."
;
this->CMakeInstance->IssueMessage(cmake::AUTHOR_WARNING, w.str(),
- this->Target->GetBacktrace());
+ this->Target->Target->GetBacktrace());
}
return true;
@@ -577,7 +583,8 @@ bool cmComputeLinkInformation::Compute()
void cmComputeLinkInformation::AddImplicitLinkInfo()
{
// The link closure lists all languages whose implicit info is needed.
- cmTarget::LinkClosure const* lc=this->Target->GetLinkClosure(this->Config);
+ cmGeneratorTarget::LinkClosure const* lc =
+ this->Target->GetLinkClosure(this->Config);
for(std::vector<std::string>::const_iterator li = lc->Languages.begin();
li != lc->Languages.end(); ++li)
{
@@ -640,9 +647,7 @@ void cmComputeLinkInformation::AddItem(std::string const& item,
if(tgt && tgt->IsLinkable())
{
- cmGeneratorTarget *gtgt = tgt->GetMakefile()
- ->GetGlobalGenerator()
- ->GetGeneratorTarget(tgt);
+ cmGeneratorTarget *gtgt = this->GlobalGenerator->GetGeneratorTarget(tgt);
// This is a CMake target. Ask the target for its real name.
if(impexe && this->LoaderFlag)
{
@@ -756,15 +761,16 @@ void cmComputeLinkInformation::AddSharedDepItem(std::string const& item,
return;
}
+ cmGeneratorTarget *gtgt = 0;
+
// Get a full path to the dependent shared library.
// Add it to the runtime path computation so that the target being
// linked will be able to find it.
std::string lib;
if(tgt)
{
- cmGeneratorTarget *gtgt = tgt->GetMakefile()
- ->GetGlobalGenerator()
- ->GetGeneratorTarget(tgt);
+ gtgt = tgt->GetMakefile()->GetGlobalGenerator()->GetGeneratorTarget(tgt);
+
lib = gtgt->GetFullPath(this->Config, this->UseImportLibrary);
this->AddLibraryRuntimeInfo(lib, tgt);
}
@@ -790,9 +796,9 @@ void cmComputeLinkInformation::AddSharedDepItem(std::string const& item,
}
if(order)
{
- if(tgt)
+ if(gtgt)
{
- std::string soName = tgt->GetSOName(this->Config);
+ std::string soName = gtgt->GetSOName(this->Config);
const char* soname = soName.empty()? 0 : soName.c_str();
order->AddRuntimeLibrary(lib, soname);
}
@@ -854,9 +860,11 @@ void cmComputeLinkInformation::ComputeLinkTypeInfo()
}
// Lookup the starting link type from the target (linked statically?).
- const char* lss = this->Target->GetProperty("LINK_SEARCH_START_STATIC");
+ const char* lss =
+ this->Target->Target->GetProperty("LINK_SEARCH_START_STATIC");
this->StartLinkType = cmSystemTools::IsOn(lss)? LinkStatic : LinkShared;
- this->CurrentLinkType = this->StartLinkType;
+ this->CurrentLinkType = LinkUnknown;
+ this->SetCurrentLinkType(this->StartLinkType);
}
//----------------------------------------------------------------------------
@@ -1140,7 +1148,7 @@ void cmComputeLinkInformation::AddFullItem(std::string const& item)
// Full path libraries should specify a valid library file name.
// See documentation of CMP0008.
std::string generator = this->GlobalGenerator->GetName();
- if(this->Target->GetPolicyStatusCMP0008() != cmPolicies::NEW &&
+ if(this->Target->Target->GetPolicyStatusCMP0008() != cmPolicies::NEW &&
(generator.find("Visual Studio") != generator.npos ||
generator.find("Xcode") != generator.npos))
{
@@ -1221,7 +1229,7 @@ bool cmComputeLinkInformation::CheckImplicitDirItem(std::string const& item)
}
// Check the policy for whether we should use the approach below.
- switch (this->Target->GetPolicyStatusCMP0060())
+ switch (this->Target->Target->GetPolicyStatusCMP0060())
{
case cmPolicies::WARN:
if (this->CMP0060Warn)
@@ -1531,7 +1539,7 @@ void cmComputeLinkInformation::HandleBadFullItem(std::string const& item,
this->OrderLinkerSearchPath->AddLinkLibrary(item);
// Produce any needed message.
- switch(this->Target->GetPolicyStatusCMP0008())
+ switch(this->Target->Target->GetPolicyStatusCMP0008())
{
case cmPolicies::WARN:
{
@@ -1548,7 +1556,7 @@ void cmComputeLinkInformation::HandleBadFullItem(std::string const& item,
<< " " << item << "\n"
<< "which is a full-path but not a valid library file name.";
this->CMakeInstance->IssueMessage(cmake::AUTHOR_WARNING, w.str(),
- this->Target->GetBacktrace());
+ this->Target->Target->GetBacktrace());
}
}
case cmPolicies::OLD:
@@ -1566,7 +1574,7 @@ void cmComputeLinkInformation::HandleBadFullItem(std::string const& item,
<< " " << item << "\n"
<< "which is a full-path but not a valid library file name.";
this->CMakeInstance->IssueMessage(cmake::FATAL_ERROR, e.str(),
- this->Target->GetBacktrace());
+ this->Target->Target->GetBacktrace());
}
break;
}
@@ -1583,7 +1591,7 @@ bool cmComputeLinkInformation::FinishLinkerSearchDirectories()
}
// Enforce policy constraints.
- switch(this->Target->GetPolicyStatusCMP0003())
+ switch(this->Target->Target->GetPolicyStatusCMP0003())
{
case cmPolicies::WARN:
if(!this->CMakeInstance->GetState()
@@ -1594,7 +1602,7 @@ bool cmComputeLinkInformation::FinishLinkerSearchDirectories()
std::ostringstream w;
this->PrintLinkPolicyDiagnosis(w);
this->CMakeInstance->IssueMessage(cmake::AUTHOR_WARNING, w.str(),
- this->Target->GetBacktrace());
+ this->Target->Target->GetBacktrace());
}
case cmPolicies::OLD:
// OLD behavior is to add the paths containing libraries with
@@ -1610,7 +1618,7 @@ bool cmComputeLinkInformation::FinishLinkerSearchDirectories()
e << cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0003) << "\n";
this->PrintLinkPolicyDiagnosis(e);
this->CMakeInstance->IssueMessage(cmake::FATAL_ERROR, e.str(),
- this->Target->GetBacktrace());
+ this->Target->Target->GetBacktrace());
return false;
}
}
@@ -1804,7 +1812,8 @@ cmComputeLinkInformation::AddLibraryRuntimeInfo(std::string const& fullPath,
// Try to get the soname of the library. Only files with this name
// could possibly conflict.
- std::string soName = target->GetSOName(this->Config);
+ cmGeneratorTarget *gtgt = this->GlobalGenerator->GetGeneratorTarget(target);
+ std::string soName = gtgt->GetSOName(this->Config);
const char* soname = soName.empty()? 0 : soName.c_str();
// Include this library in the runtime path ordering.
@@ -1911,23 +1920,24 @@ void cmComputeLinkInformation::GetRPath(std::vector<std::string>& runtimeDirs,
// build tree.
bool linking_for_install =
(for_install ||
- this->Target->GetPropertyAsBool("BUILD_WITH_INSTALL_RPATH"));
+ this->Target->Target->GetPropertyAsBool("BUILD_WITH_INSTALL_RPATH"));
bool use_install_rpath =
- (outputRuntime && this->Target->HaveInstallTreeRPATH() &&
+ (outputRuntime && this->Target->Target->HaveInstallTreeRPATH() &&
linking_for_install);
bool use_build_rpath =
- (outputRuntime && this->Target->HaveBuildTreeRPATH(this->Config) &&
+ (outputRuntime && this->Target->Target->HaveBuildTreeRPATH(this->Config) &&
!linking_for_install);
bool use_link_rpath =
outputRuntime && linking_for_install &&
!this->Makefile->IsOn("CMAKE_SKIP_INSTALL_RPATH") &&
- this->Target->GetPropertyAsBool("INSTALL_RPATH_USE_LINK_PATH");
+ this->Target->Target->GetPropertyAsBool("INSTALL_RPATH_USE_LINK_PATH");
// Construct the RPATH.
std::set<std::string> emitted;
if(use_install_rpath)
{
- const char* install_rpath = this->Target->GetProperty("INSTALL_RPATH");
+ const char* install_rpath =
+ this->Target->Target->GetProperty("INSTALL_RPATH");
cmCLI_ExpandListUnique(install_rpath, runtimeDirs, emitted);
}
if(use_build_rpath || use_link_rpath)
@@ -1999,7 +2009,7 @@ void cmComputeLinkInformation::GetRPath(std::vector<std::string>& runtimeDirs,
// Add runtime paths required by the languages to always be
// present. This is done even when skipping rpath support.
{
- cmTarget::LinkClosure const* lc =
+ cmGeneratorTarget::LinkClosure const* lc =
this->Target->GetLinkClosure(this->Config);
for(std::vector<std::string>::const_iterator li = lc->Languages.begin();
li != lc->Languages.end(); ++li)
diff --git a/Source/cmComputeLinkInformation.h b/Source/cmComputeLinkInformation.h
index 3afbb92..8b83574 100644
--- a/Source/cmComputeLinkInformation.h
+++ b/Source/cmComputeLinkInformation.h
@@ -20,6 +20,7 @@ class cmake;
class cmGlobalGenerator;
class cmMakefile;
class cmTarget;
+class cmGeneratorTarget;
class cmOrderDirectories;
/** \class cmComputeLinkInformation
@@ -28,7 +29,8 @@ class cmOrderDirectories;
class cmComputeLinkInformation
{
public:
- cmComputeLinkInformation(cmTarget const* target, const std::string& config);
+ cmComputeLinkInformation(cmGeneratorTarget const* target,
+ const std::string& config);
~cmComputeLinkInformation();
bool Compute();
@@ -72,7 +74,7 @@ private:
std::set<cmTarget const*> SharedLibrariesLinked;
// Context information.
- cmTarget const* Target;
+ cmGeneratorTarget const* Target;
cmMakefile* Makefile;
cmGlobalGenerator* GlobalGenerator;
cmake* CMakeInstance;
diff --git a/Source/cmConditionEvaluator.cxx b/Source/cmConditionEvaluator.cxx
index 420bfdf..7874803 100644
--- a/Source/cmConditionEvaluator.cxx
+++ b/Source/cmConditionEvaluator.cxx
@@ -16,7 +16,8 @@ cmConditionEvaluator::cmConditionEvaluator(cmMakefile& makefile):
Makefile(makefile),
Policy12Status(makefile.GetPolicyStatus(cmPolicies::CMP0012)),
Policy54Status(makefile.GetPolicyStatus(cmPolicies::CMP0054)),
- Policy57Status(makefile.GetPolicyStatus(cmPolicies::CMP0057))
+ Policy57Status(makefile.GetPolicyStatus(cmPolicies::CMP0057)),
+ Policy64Status(makefile.GetPolicyStatus(cmPolicies::CMP0064))
{
}
@@ -493,6 +494,29 @@ bool cmConditionEvaluator::HandleLevel1(cmArgumentList &newArgs,
this->Makefile.FindTargetToUse(argP1->GetValue())?true:false,
reducible, arg, newArgs, argP1, argP2);
}
+ // does a test exist
+ if(this->Policy64Status != cmPolicies::OLD &&
+ this->Policy64Status != cmPolicies::WARN)
+ {
+ if (this->IsKeyword("TEST", *arg) && argP1 != newArgs.end())
+ {
+ const cmTest* haveTest = this->Makefile.GetTest(argP1->c_str());
+ this->HandlePredicate(
+ haveTest?true:false,
+ reducible, arg, newArgs, argP1, argP2);
+ }
+ }
+ else if(this->Policy64Status == cmPolicies::WARN &&
+ this->IsKeyword("TEST", *arg))
+ {
+ std::ostringstream e;
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0064) << "\n";
+ e << "TEST will be interpreted as an operator "
+ "when the policy is set to NEW. "
+ "Since the policy is not set the OLD behavior will be used.";
+
+ this->Makefile.IssueMessage(cmake::AUTHOR_WARNING, e.str());
+ }
// is a variable defined
if (this->IsKeyword("DEFINED", *arg) && argP1 != newArgs.end())
{
diff --git a/Source/cmConditionEvaluator.h b/Source/cmConditionEvaluator.h
index c923d76..c4e2d11 100644
--- a/Source/cmConditionEvaluator.h
+++ b/Source/cmConditionEvaluator.h
@@ -94,6 +94,7 @@ private:
cmPolicies::PolicyStatus Policy12Status;
cmPolicies::PolicyStatus Policy54Status;
cmPolicies::PolicyStatus Policy57Status;
+ cmPolicies::PolicyStatus Policy64Status;
};
#endif
diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx
index ffb349e..9411555 100644
--- a/Source/cmCoreTryCompile.cxx
+++ b/Source/cmCoreTryCompile.cxx
@@ -470,6 +470,16 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv)
{
fprintf(fout, "set(CMAKE_POSITION_INDEPENDENT_CODE \"ON\")\n");
}
+ if (const char *lssDef = this->Makefile->GetDefinition(
+ "CMAKE_LINK_SEARCH_START_STATIC"))
+ {
+ fprintf(fout, "set(CMAKE_LINK_SEARCH_START_STATIC \"%s\")\n", lssDef);
+ }
+ if (const char *lssDef = this->Makefile->GetDefinition(
+ "CMAKE_LINK_SEARCH_END_STATIC"))
+ {
+ fprintf(fout, "set(CMAKE_LINK_SEARCH_END_STATIC \"%s\")\n", lssDef);
+ }
/* Put the executable at a known location (for COPY_FILE). */
fprintf(fout, "set(CMAKE_RUNTIME_OUTPUT_DIRECTORY \"%s\")\n",
diff --git a/Source/cmCurl.cxx b/Source/cmCurl.cxx
index 96d3547..ad0c7d3 100644
--- a/Source/cmCurl.cxx
+++ b/Source/cmCurl.cxx
@@ -13,7 +13,7 @@
#include "cmSystemTools.h"
#define check_curl_result(result, errstr) \
- if (result != CURLE_OK) \
+ if (result != CURLE_OK && result != CURLE_NOT_BUILT_IN) \
{ \
e += e.empty()? "" : "\n"; \
e += errstr; \
diff --git a/Source/cmDependsFortran.cxx b/Source/cmDependsFortran.cxx
index 13c6409..856dcd4 100644
--- a/Source/cmDependsFortran.cxx
+++ b/Source/cmDependsFortran.cxx
@@ -154,14 +154,10 @@ bool cmDependsFortran::Finalize(std::ostream& makeDepends,
const char* stamp_dir = this->TargetDirectory.c_str();
// Get the directory in which module files will be created.
- const char* mod_dir;
cmMakefile* mf = this->LocalGenerator->GetMakefile();
- if(const char* target_mod_dir =
- mf->GetDefinition("CMAKE_Fortran_TARGET_MODULE_DIR"))
- {
- mod_dir = target_mod_dir;
- }
- else
+ std::string mod_dir =
+ mf->GetSafeDefinition("CMAKE_Fortran_TARGET_MODULE_DIR");
+ if (mod_dir.empty())
{
mod_dir =
this->LocalGenerator->GetMakefile()->GetCurrentBinaryDirectory();
@@ -356,7 +352,8 @@ bool
cmDependsFortran
::WriteDependenciesReal(const char *obj,
cmFortranSourceInfo const& info,
- const char* mod_dir, const char* stamp_dir,
+ std::string const& mod_dir,
+ const char* stamp_dir,
std::ostream& makeDepends,
std::ostream& internalDepends)
{
diff --git a/Source/cmDependsFortran.h b/Source/cmDependsFortran.h
index d6ec7d7..a8a4013 100644
--- a/Source/cmDependsFortran.h
+++ b/Source/cmDependsFortran.h
@@ -66,7 +66,8 @@ protected:
// Actually write the depenencies to the streams.
bool WriteDependenciesReal(const char *obj,
cmFortranSourceInfo const& info,
- const char* mod_dir, const char* stamp_dir,
+ std::string const& mod_dir,
+ const char* stamp_dir,
std::ostream& makeDepends,
std::ostream& internalDepends);
diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx
index 355fc00..fed0dbc 100644
--- a/Source/cmExportBuildFileGenerator.cxx
+++ b/Source/cmExportBuildFileGenerator.cxx
@@ -27,6 +27,7 @@ cmExportBuildFileGenerator::cmExportBuildFileGenerator()
//----------------------------------------------------------------------------
bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os)
{
+ std::vector<cmGeneratorTarget*> allTargets;
{
std::string expectedTargets;
std::string sep;
@@ -68,7 +69,8 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os)
tei = this->Exports.begin();
tei != this->Exports.end(); ++tei)
{
- cmTarget* te = (*tei)->Target;
+ cmGeneratorTarget* gte = *tei;
+ cmTarget* te = gte->Target;
this->GenerateImportTargetCode(os, te);
te->AppendBuildInterfaceIncludes();
@@ -104,7 +106,7 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os)
cmGeneratorExpression::BuildInterface,
properties, missingTargets);
}
- this->PopulateCompatibleInterfaceProperties(te, properties);
+ this->PopulateCompatibleInterfaceProperties(gte, properties);
this->GenerateInterfaceProperties(te, os, properties);
}
@@ -331,12 +333,12 @@ cmExportBuildFileGenerator
}
std::string
-cmExportBuildFileGenerator::InstallNameDir(cmTarget* target,
+cmExportBuildFileGenerator::InstallNameDir(cmGeneratorTarget* target,
const std::string& config)
{
std::string install_name_dir;
- cmMakefile* mf = target->GetMakefile();
+ cmMakefile* mf = target->Target->GetMakefile();
if(mf->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME"))
{
install_name_dir =
diff --git a/Source/cmExportBuildFileGenerator.h b/Source/cmExportBuildFileGenerator.h
index 4d8e062..ff3d2e1 100644
--- a/Source/cmExportBuildFileGenerator.h
+++ b/Source/cmExportBuildFileGenerator.h
@@ -71,7 +71,8 @@ protected:
cmGeneratorTarget* target,
ImportPropertyMap& properties);
- std::string InstallNameDir(cmTarget* target, const std::string& config);
+ std::string InstallNameDir(cmGeneratorTarget* target,
+ const std::string& config);
std::vector<std::string>
FindNamespaces(cmMakefile* mf, const std::string& name);
diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx
index a33cd59..cae60b7 100644
--- a/Source/cmExportFileGenerator.cxx
+++ b/Source/cmExportFileGenerator.cxx
@@ -525,7 +525,7 @@ void getPropertyContents(cmTarget const* tgt, const std::string& prop,
}
//----------------------------------------------------------------------------
-void getCompatibleInterfaceProperties(cmTarget *target,
+void getCompatibleInterfaceProperties(cmGeneratorTarget *target,
std::set<std::string> &ifaceProperties,
const std::string& config)
{
@@ -533,7 +533,7 @@ void getCompatibleInterfaceProperties(cmTarget *target,
if (!info)
{
- cmMakefile* mf = target->GetMakefile();
+ cmMakefile* mf = target->Target->GetMakefile();
std::ostringstream e;
e << "Exporting the target \"" << target->GetName() << "\" is not "
"allowed since its linker language cannot be determined";
@@ -568,9 +568,10 @@ void getCompatibleInterfaceProperties(cmTarget *target,
//----------------------------------------------------------------------------
void cmExportFileGenerator::PopulateCompatibleInterfaceProperties(
- cmTarget *target,
+ cmGeneratorTarget *gtarget,
ImportPropertyMap &properties)
{
+ cmTarget *target = gtarget->Target;
this->PopulateInterfaceProperty("COMPATIBLE_INTERFACE_BOOL",
target, properties);
this->PopulateInterfaceProperty("COMPATIBLE_INTERFACE_STRING",
@@ -591,7 +592,7 @@ void cmExportFileGenerator::PopulateCompatibleInterfaceProperties(
if (target->GetType() != cmTarget::INTERFACE_LIBRARY)
{
- getCompatibleInterfaceProperties(target, ifaceProperties, "");
+ getCompatibleInterfaceProperties(gtarget, ifaceProperties, "");
std::vector<std::string> configNames;
target->GetMakefile()->GetConfigurations(configNames);
@@ -599,7 +600,7 @@ void cmExportFileGenerator::PopulateCompatibleInterfaceProperties(
for (std::vector<std::string>::const_iterator ci = configNames.begin();
ci != configNames.end(); ++ci)
{
- getCompatibleInterfaceProperties(target, ifaceProperties, *ci);
+ getCompatibleInterfaceProperties(gtarget, ifaceProperties, *ci);
}
}
@@ -888,14 +889,14 @@ cmExportFileGenerator
{
std::string prop;
std::string value;
- if(target->Target->HasSOName(config))
+ if(target->HasSOName(config))
{
if(mf->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME"))
{
- value = this->InstallNameDir(target->Target, config);
+ value = this->InstallNameDir(target, config);
}
prop = "IMPORTED_SONAME";
- value += target->Target->GetSOName(config);
+ value += target->GetSOName(config);
}
else
{
diff --git a/Source/cmExportFileGenerator.h b/Source/cmExportFileGenerator.h
index 2f33200..44f779b 100644
--- a/Source/cmExportFileGenerator.h
+++ b/Source/cmExportFileGenerator.h
@@ -132,7 +132,7 @@ protected:
std::vector<std::string> &missingTargets);
void PopulateInterfaceProperty(const std::string& propName, cmTarget *target,
ImportPropertyMap &properties);
- void PopulateCompatibleInterfaceProperties(cmTarget *target,
+ void PopulateCompatibleInterfaceProperties(cmGeneratorTarget *target,
ImportPropertyMap &properties);
void GenerateInterfaceProperties(cmTarget const* target, std::ostream& os,
const ImportPropertyMap &properties);
@@ -200,7 +200,7 @@ private:
virtual void ReplaceInstallPrefix(std::string &input);
- virtual std::string InstallNameDir(cmTarget* target,
+ virtual std::string InstallNameDir(cmGeneratorTarget* target,
const std::string& config) = 0;
};
diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx
index 6c7d97e..d55be11 100644
--- a/Source/cmExportInstallFileGenerator.cxx
+++ b/Source/cmExportInstallFileGenerator.cxx
@@ -193,7 +193,11 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os)
this->PopulateInterfaceProperty("INTERFACE_POSITION_INDEPENDENT_CODE",
te, properties);
- this->PopulateCompatibleInterfaceProperties(te, properties);
+ cmGeneratorTarget *gtgt = te->GetMakefile()
+ ->GetGlobalGenerator()
+ ->GetGeneratorTarget(te);
+
+ this->PopulateCompatibleInterfaceProperties(gtgt, properties);
this->GenerateInterfaceProperties(te, os, properties);
}
@@ -358,7 +362,7 @@ cmExportInstallFileGenerator
if(!properties.empty())
{
// Get the rest of the target details.
- cmGeneratorTarget *gtgt = te->Target->GetMakefile()->GetLocalGenerator()
+ cmGeneratorTarget *gtgt = te->Target->GetMakefile()
->GetGlobalGenerator()->GetGeneratorTarget(te->Target);
this->SetImportDetailProperties(config, suffix,
gtgt, properties, missingTargets);
@@ -398,7 +402,7 @@ cmExportInstallFileGenerator
}
// Get the target to be installed.
- cmTarget* target = itgen->GetTarget();
+ cmTarget* target = itgen->GetTarget()->Target;
// Construct the installed location of the target.
std::string dest = itgen->GetDestination(config);
@@ -542,12 +546,12 @@ cmExportInstallFileGenerator
}
std::string
-cmExportInstallFileGenerator::InstallNameDir(cmTarget* target,
+cmExportInstallFileGenerator::InstallNameDir(cmGeneratorTarget* target,
const std::string&)
{
std::string install_name_dir;
- cmMakefile* mf = target->GetMakefile();
+ cmMakefile* mf = target->Target->GetMakefile();
if(mf->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME"))
{
install_name_dir =
diff --git a/Source/cmExportInstallFileGenerator.h b/Source/cmExportInstallFileGenerator.h
index 6f86ac9..b06fee5 100644
--- a/Source/cmExportInstallFileGenerator.h
+++ b/Source/cmExportInstallFileGenerator.h
@@ -83,7 +83,8 @@ protected:
std::set<std::string>& importedLocations
);
- std::string InstallNameDir(cmTarget* target, const std::string& config);
+ std::string InstallNameDir(cmGeneratorTarget* target,
+ const std::string& config);
cmInstallExportGenerator* IEGen;
diff --git a/Source/cmExportLibraryDependenciesCommand.cxx b/Source/cmExportLibraryDependenciesCommand.cxx
index cb150a7..fde8fb1 100644
--- a/Source/cmExportLibraryDependenciesCommand.cxx
+++ b/Source/cmExportLibraryDependenciesCommand.cxx
@@ -11,7 +11,6 @@
============================================================================*/
#include "cmExportLibraryDependenciesCommand.h"
#include "cmGlobalGenerator.h"
-#include "cmLocalGenerator.h"
#include "cmGeneratedFileStream.h"
#include "cmake.h"
#include "cmVersion.h"
@@ -82,15 +81,14 @@ void cmExportLibraryDependenciesCommand::ConstFinalPass() const
// the project.
cmake* cm = this->Makefile->GetCMakeInstance();
cmGlobalGenerator* global = cm->GetGlobalGenerator();
- const std::vector<cmLocalGenerator *>& locals = global->GetLocalGenerators();
+ const std::vector<cmMakefile*>& locals = global->GetMakefiles();
std::map<std::string, std::string> libDepsOld;
std::map<std::string, std::string> libDepsNew;
std::map<std::string, std::string> libTypes;
- for(std::vector<cmLocalGenerator *>::const_iterator i = locals.begin();
+ for(std::vector<cmMakefile*>::const_iterator i = locals.begin();
i != locals.end(); ++i)
{
- const cmLocalGenerator* gen = *i;
- const cmTargets &tgts = gen->GetMakefile()->GetTargets();
+ const cmTargets &tgts = (*i)->GetTargets();
for(cmTargets::const_iterator l = tgts.begin();
l != tgts.end(); ++l)
{
diff --git a/Source/cmExportTryCompileFileGenerator.cxx b/Source/cmExportTryCompileFileGenerator.cxx
index 94831f8..ba66531 100644
--- a/Source/cmExportTryCompileFileGenerator.cxx
+++ b/Source/cmExportTryCompileFileGenerator.cxx
@@ -125,12 +125,12 @@ cmExportTryCompileFileGenerator::PopulateProperties(cmTarget const* target,
}
std::string
-cmExportTryCompileFileGenerator::InstallNameDir(cmTarget* target,
+cmExportTryCompileFileGenerator::InstallNameDir(cmGeneratorTarget* target,
const std::string& config)
{
std::string install_name_dir;
- cmMakefile* mf = target->GetMakefile();
+ cmMakefile* mf = target->Target->GetMakefile();
if(mf->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME"))
{
install_name_dir =
diff --git a/Source/cmExportTryCompileFileGenerator.h b/Source/cmExportTryCompileFileGenerator.h
index 0d84896..8838eca 100644
--- a/Source/cmExportTryCompileFileGenerator.h
+++ b/Source/cmExportTryCompileFileGenerator.h
@@ -9,8 +9,8 @@
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the License for more information.
============================================================================*/
-#ifndef cmExportInstallFileGenerator_h
-#define cmExportInstallFileGenerator_h
+#ifndef cmExportTryCompileFileGenerator_h
+#define cmExportTryCompileFileGenerator_h
#include "cmExportFileGenerator.h"
@@ -45,7 +45,7 @@ protected:
ImportPropertyMap& properties,
std::set<cmTarget const*> &emitted);
- std::string InstallNameDir(cmTarget* target,
+ std::string InstallNameDir(cmGeneratorTarget* target,
const std::string& config);
private:
std::string FindTargets(const std::string& prop, cmTarget const* tgt,
diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx
index 0daed66..87faf84 100644
--- a/Source/cmFileCommand.cxx
+++ b/Source/cmFileCommand.cxx
@@ -3573,11 +3573,8 @@ void cmFileCommand::AddEvaluationFile(const std::string &inputName,
cmsys::auto_ptr<cmCompiledGeneratorExpression> conditionCge
= conditionGe.Parse(condition);
- this->Makefile->GetGlobalGenerator()->AddEvaluationFile(inputName,
- outputCge,
- this->Makefile,
- conditionCge,
- inputIsContent);
+ this->Makefile->AddEvaluationFile(inputName, outputCge,
+ conditionCge, inputIsContent);
}
//----------------------------------------------------------------------------
diff --git a/Source/cmGeneratorExpressionEvaluationFile.cxx b/Source/cmGeneratorExpressionEvaluationFile.cxx
index 92ff314..e4d9f10 100644
--- a/Source/cmGeneratorExpressionEvaluationFile.cxx
+++ b/Source/cmGeneratorExpressionEvaluationFile.cxx
@@ -25,19 +25,18 @@
cmGeneratorExpressionEvaluationFile::cmGeneratorExpressionEvaluationFile(
const std::string &input,
cmsys::auto_ptr<cmCompiledGeneratorExpression> outputFileExpr,
- cmMakefile *makefile,
cmsys::auto_ptr<cmCompiledGeneratorExpression> condition,
bool inputIsContent)
: Input(input),
OutputFileExpr(outputFileExpr),
- Makefile(makefile),
Condition(condition),
InputIsContent(inputIsContent)
{
}
//----------------------------------------------------------------------------
-void cmGeneratorExpressionEvaluationFile::Generate(const std::string& config,
+void cmGeneratorExpressionEvaluationFile::Generate(cmLocalGenerator* lg,
+ const std::string& config,
const std::string& lang,
cmCompiledGeneratorExpression* inputExpression,
std::map<std::string, std::string> &outputFiles, mode_t perm)
@@ -45,7 +44,8 @@ void cmGeneratorExpressionEvaluationFile::Generate(const std::string& config,
std::string rawCondition = this->Condition->GetInput();
if (!rawCondition.empty())
{
- std::string condResult = this->Condition->Evaluate(this->Makefile, config,
+ std::string condResult = this->Condition->Evaluate(lg->GetMakefile(),
+ config,
false, 0, 0, 0, lang);
if (condResult == "0")
{
@@ -56,16 +56,17 @@ void cmGeneratorExpressionEvaluationFile::Generate(const std::string& config,
std::ostringstream e;
e << "Evaluation file condition \"" << rawCondition << "\" did "
"not evaluate to valid content. Got \"" << condResult << "\".";
- this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+ lg->IssueMessage(cmake::FATAL_ERROR, e.str());
return;
}
}
const std::string outputFileName
- = this->OutputFileExpr->Evaluate(this->Makefile, config,
+ = this->OutputFileExpr->Evaluate(lg->GetMakefile(), config,
false, 0, 0, 0, lang);
const std::string outputContent
- = inputExpression->Evaluate(this->Makefile, config,
+ = inputExpression->Evaluate(lg->GetMakefile(),
+ config,
false, 0, 0, 0, lang);
std::map<std::string, std::string>::iterator it
@@ -81,11 +82,11 @@ void cmGeneratorExpressionEvaluationFile::Generate(const std::string& config,
e << "Evaluation file to be written multiple times for different "
"configurations or languages with different content:\n "
<< outputFileName;
- this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+ lg->IssueMessage(cmake::FATAL_ERROR, e.str());
return;
}
- this->Makefile->AddCMakeOutputFile(outputFileName.c_str());
+ lg->GetMakefile()->AddCMakeOutputFile(outputFileName.c_str());
this->Files.push_back(outputFileName);
outputFiles[outputFileName] = outputContent;
@@ -100,18 +101,19 @@ void cmGeneratorExpressionEvaluationFile::Generate(const std::string& config,
//----------------------------------------------------------------------------
void cmGeneratorExpressionEvaluationFile::CreateOutputFile(
- std::string const& config)
+ cmLocalGenerator *lg, std::string const& config)
{
std::vector<std::string> enabledLanguages;
- cmGlobalGenerator *gg = this->Makefile->GetGlobalGenerator();
+ cmGlobalGenerator *gg = lg->GetGlobalGenerator();
gg->GetEnabledLanguages(enabledLanguages);
for(std::vector<std::string>::const_iterator le = enabledLanguages.begin();
le != enabledLanguages.end(); ++le)
{
- std::string name = this->OutputFileExpr->Evaluate(this->Makefile, config,
+ std::string name = this->OutputFileExpr->Evaluate(lg->GetMakefile(),
+ config,
false, 0, 0, 0, *le);
- cmSourceFile* sf = this->Makefile->GetOrCreateSource(name);
+ cmSourceFile* sf = lg->GetMakefile()->GetOrCreateSource(name);
sf->SetProperty("GENERATED", "1");
gg->SetFilenameTargetDepends(sf,
@@ -120,7 +122,7 @@ void cmGeneratorExpressionEvaluationFile::CreateOutputFile(
}
//----------------------------------------------------------------------------
-void cmGeneratorExpressionEvaluationFile::Generate()
+void cmGeneratorExpressionEvaluationFile::Generate(cmLocalGenerator *lg)
{
mode_t perm = 0;
std::string inputContent;
@@ -130,14 +132,14 @@ void cmGeneratorExpressionEvaluationFile::Generate()
}
else
{
- this->Makefile->AddCMakeDependFile(this->Input.c_str());
+ lg->GetMakefile()->AddCMakeDependFile(this->Input.c_str());
cmSystemTools::GetPermissions(this->Input.c_str(), perm);
cmsys::ifstream fin(this->Input.c_str());
if(!fin)
{
std::ostringstream e;
e << "Evaluation file \"" << this->Input << "\" cannot be read.";
- this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+ lg->GetMakefile()->IssueMessage(cmake::FATAL_ERROR, e.str());
return;
}
@@ -159,7 +161,7 @@ void cmGeneratorExpressionEvaluationFile::Generate()
std::map<std::string, std::string> outputFiles;
std::vector<std::string> allConfigs;
- this->Makefile->GetConfigurations(allConfigs);
+ lg->GetMakefile()->GetConfigurations(allConfigs);
if (allConfigs.empty())
{
@@ -167,7 +169,7 @@ void cmGeneratorExpressionEvaluationFile::Generate()
}
std::vector<std::string> enabledLanguages;
- cmGlobalGenerator *gg = this->Makefile->GetGlobalGenerator();
+ cmGlobalGenerator *gg = lg->GetGlobalGenerator();
gg->GetEnabledLanguages(enabledLanguages);
for(std::vector<std::string>::const_iterator le = enabledLanguages.begin();
@@ -176,7 +178,7 @@ void cmGeneratorExpressionEvaluationFile::Generate()
for(std::vector<std::string>::const_iterator li = allConfigs.begin();
li != allConfigs.end(); ++li)
{
- this->Generate(*li, *le, inputExpression.get(), outputFiles, perm);
+ this->Generate(lg, *li, *le, inputExpression.get(), outputFiles, perm);
if(cmSystemTools::GetFatalErrorOccured())
{
return;
diff --git a/Source/cmGeneratorExpressionEvaluationFile.h b/Source/cmGeneratorExpressionEvaluationFile.h
index 5d8b54c..ad41274 100644
--- a/Source/cmGeneratorExpressionEvaluationFile.h
+++ b/Source/cmGeneratorExpressionEvaluationFile.h
@@ -18,31 +18,32 @@
#include "cmGeneratorExpression.h"
+class cmLocalGenerator;
+
//----------------------------------------------------------------------------
class cmGeneratorExpressionEvaluationFile
{
public:
cmGeneratorExpressionEvaluationFile(const std::string &input,
cmsys::auto_ptr<cmCompiledGeneratorExpression> outputFileExpr,
- cmMakefile *makefile,
cmsys::auto_ptr<cmCompiledGeneratorExpression> condition,
bool inputIsContent);
- void Generate();
+ void Generate(cmLocalGenerator* lg);
std::vector<std::string> GetFiles() const { return this->Files; }
- void CreateOutputFile(std::string const& config);
+ void CreateOutputFile(cmLocalGenerator* lg, std::string const& config);
private:
- void Generate(const std::string& config, const std::string& lang,
- cmCompiledGeneratorExpression* inputExpression,
- std::map<std::string, std::string> &outputFiles, mode_t perm);
+ void Generate(cmLocalGenerator* lg, const std::string& config,
+ const std::string& lang,
+ cmCompiledGeneratorExpression* inputExpression,
+ std::map<std::string, std::string> &outputFiles, mode_t perm);
private:
const std::string Input;
const cmsys::auto_ptr<cmCompiledGeneratorExpression> OutputFileExpr;
- cmMakefile *Makefile;
const cmsys::auto_ptr<cmCompiledGeneratorExpression> Condition;
std::vector<std::string> Files;
const bool InputIsContent;
diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx
index 3daa7b8..03bc83a 100644
--- a/Source/cmGeneratorExpressionNode.cxx
+++ b/Source/cmGeneratorExpressionNode.cxx
@@ -990,6 +990,9 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
assert(target);
+ cmGeneratorTarget* gtgt =
+ context->Makefile->GetGlobalGenerator()->GetGeneratorTarget(target);
+
if (propertyName == "LINKER_LANGUAGE")
{
if (target->LinkLanguagePropagatesToDependents() &&
@@ -1001,7 +1004,7 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
"link libraries for a static library");
return std::string();
}
- return target->GetLinkerLanguage(context->Config);
+ return gtgt->GetLinkerLanguage(context->Config);
}
cmGeneratorExpressionDAGChecker dagChecker(context->Backtrace,
@@ -1117,7 +1120,7 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
}
else if(!interfacePropertyName.empty())
{
- if(cmTarget::LinkImplementationLibraries const* impl =
+ if(cmLinkImplementationLibraries const* impl =
target->GetLinkImplementationLibraries(context->Config))
{
linkedTargetsContent =
@@ -1135,40 +1138,40 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
{
return linkedTargetsContent;
}
- if (target->IsLinkInterfaceDependentBoolProperty(propertyName,
- context->Config))
+ if (gtgt->IsLinkInterfaceDependentBoolProperty(propertyName,
+ context->Config))
{
context->HadContextSensitiveCondition = true;
- return target->GetLinkInterfaceDependentBoolProperty(
+ return gtgt->GetLinkInterfaceDependentBoolProperty(
propertyName,
context->Config) ? "1" : "0";
}
- if (target->IsLinkInterfaceDependentStringProperty(propertyName,
- context->Config))
+ if (gtgt->IsLinkInterfaceDependentStringProperty(propertyName,
+ context->Config))
{
context->HadContextSensitiveCondition = true;
const char *propContent =
- target->GetLinkInterfaceDependentStringProperty(
+ gtgt->GetLinkInterfaceDependentStringProperty(
propertyName,
context->Config);
return propContent ? propContent : "";
}
- if (target->IsLinkInterfaceDependentNumberMinProperty(propertyName,
- context->Config))
+ if (gtgt->IsLinkInterfaceDependentNumberMinProperty(propertyName,
+ context->Config))
{
context->HadContextSensitiveCondition = true;
const char *propContent =
- target->GetLinkInterfaceDependentNumberMinProperty(
+ gtgt->GetLinkInterfaceDependentNumberMinProperty(
propertyName,
context->Config);
return propContent ? propContent : "";
}
- if (target->IsLinkInterfaceDependentNumberMaxProperty(propertyName,
- context->Config))
+ if (gtgt->IsLinkInterfaceDependentNumberMaxProperty(propertyName,
+ context->Config))
{
context->HadContextSensitiveCondition = true;
const char *propContent =
- target->GetLinkInterfaceDependentNumberMaxProperty(
+ gtgt->GetLinkInterfaceDependentNumberMaxProperty(
propertyName,
context->Config);
return propContent ? propContent : "";
@@ -1180,22 +1183,22 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
if (!target->IsImported()
&& dagCheckerParent && !dagCheckerParent->EvaluatingLinkLibraries())
{
- if (target->IsLinkInterfaceDependentNumberMinProperty(propertyName,
- context->Config))
+ if (gtgt->IsLinkInterfaceDependentNumberMinProperty(propertyName,
+ context->Config))
{
context->HadContextSensitiveCondition = true;
const char *propContent =
- target->GetLinkInterfaceDependentNumberMinProperty(
+ gtgt->GetLinkInterfaceDependentNumberMinProperty(
propertyName,
context->Config);
return propContent ? propContent : "";
}
- if (target->IsLinkInterfaceDependentNumberMaxProperty(propertyName,
- context->Config))
+ if (gtgt->IsLinkInterfaceDependentNumberMaxProperty(propertyName,
+ context->Config))
{
context->HadContextSensitiveCondition = true;
const char *propContent =
- target->GetLinkInterfaceDependentNumberMaxProperty(
+ gtgt->GetLinkInterfaceDependentNumberMaxProperty(
propertyName,
context->Config);
return propContent ? propContent : "";
@@ -1369,8 +1372,6 @@ static const struct CompileFeaturesNode : public cmGeneratorExpressionNode
bool evalLL = dagChecker && dagChecker->EvaluatingLinkLibraries();
- std::string result;
-
for (LangMap::const_iterator lit = testedFeatures.begin();
lit != testedFeatures.end(); ++lit)
{
@@ -1586,7 +1587,7 @@ struct TargetFilesystemArtifactResultCreator<ArtifactSonameTag>
}
std::string result = target->Target->GetDirectory(context->Config);
result += "/";
- result += target->Target->GetSOName(context->Config);
+ result += target->GetSOName(context->Config);
return result;
}
};
@@ -1599,7 +1600,14 @@ struct TargetFilesystemArtifactResultCreator<ArtifactPdbTag>
cmGeneratorExpressionContext *context,
const GeneratorExpressionContent *content)
{
- std::string language = target->Target->GetLinkerLanguage(context->Config);
+ if (target->IsImported())
+ {
+ ::reportError(context, content->GetOriginalExpression(),
+ "TARGET_PDB_FILE not allowed for IMPORTED targets.");
+ return std::string();
+ }
+
+ std::string language = target->GetLinkerLanguage(context->Config);
std::string pdbSupportVar = "CMAKE_" + language + "_LINKER_SUPPORTS_PDB";
@@ -1624,7 +1632,7 @@ struct TargetFilesystemArtifactResultCreator<ArtifactPdbTag>
std::string result = target->Target->GetPDBDirectory(context->Config);
result += "/";
- result += target->Target->GetPDBName(context->Config);
+ result += target->GetPDBName(context->Config);
return result;
}
};
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index edd89e8..299c112 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -24,11 +24,19 @@
#include <queue>
+#include <errno.h>
#include "assert.h"
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+#include <cmsys/hash_set.hxx>
+#define UNORDERED_SET cmsys::hash_set
+#else
+#define UNORDERED_SET std::set
+#endif
+
//----------------------------------------------------------------------------
void reportBadObjLib(std::vector<cmSourceFile*> const& badObjLib,
- cmTarget *target, cmake *cm)
+ cmGeneratorTarget const* target, cmake *cm)
{
if(!badObjLib.empty())
{
@@ -42,7 +50,7 @@ void reportBadObjLib(std::vector<cmSourceFile*> const& badObjLib,
e << "but may contain only sources that compile, header files, and "
"other files that would not affect linking of a normal library.";
cm->IssueMessage(cmake::FATAL_ERROR, e.str(),
- target->GetBacktrace());
+ target->Target->GetBacktrace());
}
}
@@ -125,14 +133,14 @@ struct TagVisitor
{
DataType& Data;
std::vector<cmSourceFile*> BadObjLibFiles;
- cmTarget *Target;
+ cmGeneratorTarget const* Target;
cmGlobalGenerator *GlobalGenerator;
cmsys::RegularExpression Header;
bool IsObjLib;
- TagVisitor(cmTarget *target, DataType& data)
+ TagVisitor(cmGeneratorTarget const* target, DataType& data)
: Data(data), Target(target),
- GlobalGenerator(target->GetMakefile()->GetGlobalGenerator()),
+ GlobalGenerator(target->GetLocalGenerator()->GetGlobalGenerator()),
Header(CM_HEADER_REGEX),
IsObjLib(target->GetType() == cmTarget::OBJECT_LIBRARY)
{
@@ -226,7 +234,13 @@ cmGeneratorTarget::cmGeneratorTarget(cmTarget* t, cmLocalGenerator* lg)
{
this->Makefile = this->Target->GetMakefile();
this->LocalGenerator = lg;
- this->GlobalGenerator = this->Makefile->GetGlobalGenerator();
+ this->GlobalGenerator = this->LocalGenerator->GetGlobalGenerator();
+}
+
+cmGeneratorTarget::~cmGeneratorTarget()
+{
+ cmDeleteAll(this->LinkInformation);
+ this->LinkInformation.clear();
}
cmLocalGenerator* cmGeneratorTarget::GetLocalGenerator() const
@@ -253,6 +267,54 @@ const char *cmGeneratorTarget::GetProperty(const std::string& prop) const
}
//----------------------------------------------------------------------------
+std::string cmGeneratorTarget::GetOutputName(const std::string& config,
+ bool implib) const
+{
+ std::vector<std::string> props;
+ std::string type = this->Target->GetOutputTargetType(implib);
+ std::string configUpper = cmSystemTools::UpperCase(config);
+ if(!type.empty() && !configUpper.empty())
+ {
+ // <ARCHIVE|LIBRARY|RUNTIME>_OUTPUT_NAME_<CONFIG>
+ props.push_back(type + "_OUTPUT_NAME_" + configUpper);
+ }
+ if(!type.empty())
+ {
+ // <ARCHIVE|LIBRARY|RUNTIME>_OUTPUT_NAME
+ props.push_back(type + "_OUTPUT_NAME");
+ }
+ if(!configUpper.empty())
+ {
+ // OUTPUT_NAME_<CONFIG>
+ props.push_back("OUTPUT_NAME_" + configUpper);
+ // <CONFIG>_OUTPUT_NAME
+ props.push_back(configUpper + "_OUTPUT_NAME");
+ }
+ // OUTPUT_NAME
+ props.push_back("OUTPUT_NAME");
+
+ std::string outName;
+ for(std::vector<std::string>::const_iterator i = props.begin();
+ i != props.end(); ++i)
+ {
+ if (const char* outNameProp = this->Target->GetProperty(*i))
+ {
+ outName = outNameProp;
+ break;
+ }
+ }
+
+ if (outName.empty())
+ {
+ outName = this->GetName();
+ }
+
+ cmGeneratorExpression ge;
+ cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(outName);
+ return cge->Evaluate(this->Makefile, config);
+}
+
+//----------------------------------------------------------------------------
std::vector<cmSourceFile*> const*
cmGeneratorTarget::GetSourceDepends(cmSourceFile const* sf) const
{
@@ -300,7 +362,7 @@ static void handleSystemIncludesDep(cmMakefile *mf, cmTarget const* depTgt,
{ \
std::vector<cmSourceFile*> sourceFiles; \
this->Target->GetSourceFiles(sourceFiles, config); \
- TagVisitor<DATA ## Tag DATATYPE> visitor(this->Target, data); \
+ TagVisitor<DATA ## Tag DATATYPE> visitor(this, data); \
for(std::vector<cmSourceFile*>::const_iterator si = sourceFiles.begin(); \
si != sourceFiles.end(); ++si) \
{ \
@@ -560,7 +622,7 @@ const char* cmGeneratorTarget::GetLocationForBuild() const
if(this->Target->IsAppBundleOnApple())
{
- std::string macdir = this->Target->BuildMacContentDirectory("", "",
+ std::string macdir = this->BuildMacContentDirectory("", "",
false);
if(!macdir.empty())
{
@@ -569,7 +631,7 @@ const char* cmGeneratorTarget::GetLocationForBuild() const
}
}
location += "/";
- location += this->Target->GetFullName("", false);
+ location += this->GetFullName("", false);
return location.c_str();
}
@@ -611,7 +673,7 @@ bool cmGeneratorTarget::IsSystemIncludeDirectory(const std::string& dir,
}
std::vector<cmTarget const*> const& deps =
- this->Target->GetLinkImplementationClosure(config);
+ this->GetLinkImplementationClosure(config);
for(std::vector<cmTarget const*>::const_iterator
li = deps.begin(), le = deps.end(); li != le; ++li)
{
@@ -651,6 +713,692 @@ void cmGeneratorTarget::GetSourceFiles(std::vector<cmSourceFile*> &files,
//----------------------------------------------------------------------------
std::string
+cmGeneratorTarget::GetCompilePDBName(const std::string& config) const
+{
+ std::string prefix;
+ std::string base;
+ std::string suffix;
+ this->GetFullNameInternal(config, false, prefix, base, suffix);
+
+ // Check for a per-configuration output directory target property.
+ std::string configUpper = cmSystemTools::UpperCase(config);
+ std::string configProp = "COMPILE_PDB_NAME_";
+ configProp += configUpper;
+ const char* config_name = this->Target->GetProperty(configProp);
+ if(config_name && *config_name)
+ {
+ return prefix + config_name + ".pdb";
+ }
+
+ const char* name = this->Target->GetProperty("COMPILE_PDB_NAME");
+ if(name && *name)
+ {
+ return prefix + name + ".pdb";
+ }
+
+ return "";
+}
+
+//----------------------------------------------------------------------------
+std::string
+cmGeneratorTarget::GetCompilePDBPath(const std::string& config) const
+{
+ std::string dir = this->GetCompilePDBDirectory(config);
+ std::string name = this->GetCompilePDBName(config);
+ if(dir.empty() && !name.empty())
+ {
+ dir = this->Target->GetPDBDirectory(config);
+ }
+ if(!dir.empty())
+ {
+ dir += "/";
+ }
+ return dir + name;
+}
+
+//----------------------------------------------------------------------------
+bool cmGeneratorTarget::HasSOName(const std::string& config) const
+{
+ // soname is supported only for shared libraries and modules,
+ // and then only when the platform supports an soname flag.
+ return ((this->GetType() == cmTarget::SHARED_LIBRARY ||
+ this->GetType() == cmTarget::MODULE_LIBRARY) &&
+ !this->GetPropertyAsBool("NO_SONAME") &&
+ this->Makefile->GetSONameFlag(this->GetLinkerLanguage(config)));
+}
+
+//----------------------------------------------------------------------------
+bool
+cmGeneratorTarget::NeedRelinkBeforeInstall(const std::string& config) const
+{
+ // Only executables and shared libraries can have an rpath and may
+ // need relinking.
+ if(this->GetType() != cmTarget::EXECUTABLE &&
+ this->GetType() != cmTarget::SHARED_LIBRARY &&
+ this->GetType() != cmTarget::MODULE_LIBRARY)
+ {
+ return false;
+ }
+
+ // If there is no install location this target will not be installed
+ // and therefore does not need relinking.
+ if(!this->Target->GetHaveInstallRule())
+ {
+ return false;
+ }
+
+ // If skipping all rpaths completely then no relinking is needed.
+ if(this->Makefile->IsOn("CMAKE_SKIP_RPATH"))
+ {
+ return false;
+ }
+
+ // If building with the install-tree rpath no relinking is needed.
+ if(this->GetPropertyAsBool("BUILD_WITH_INSTALL_RPATH"))
+ {
+ return false;
+ }
+
+ // If chrpath is going to be used no relinking is needed.
+ if(this->IsChrpathUsed(config))
+ {
+ return false;
+ }
+
+ // Check for rpath support on this platform.
+ std::string ll = this->GetLinkerLanguage(config);
+ if(!ll.empty())
+ {
+ std::string flagVar = "CMAKE_SHARED_LIBRARY_RUNTIME_";
+ flagVar += ll;
+ flagVar += "_FLAG";
+ if(!this->Makefile->IsSet(flagVar))
+ {
+ // There is no rpath support on this platform so nothing needs
+ // relinking.
+ return false;
+ }
+ }
+ else
+ {
+ // No linker language is known. This error will be reported by
+ // other code.
+ return false;
+ }
+
+ // If either a build or install tree rpath is set then the rpath
+ // will likely change between the build tree and install tree and
+ // this target must be relinked.
+ return this->Target->HaveBuildTreeRPATH(config)
+ || this->Target->HaveInstallTreeRPATH();
+}
+
+//----------------------------------------------------------------------------
+bool cmGeneratorTarget::IsChrpathUsed(const std::string& config) const
+{
+ // Only certain target types have an rpath.
+ if(!(this->GetType() == cmTarget::SHARED_LIBRARY ||
+ this->GetType() == cmTarget::MODULE_LIBRARY ||
+ this->GetType() == cmTarget::EXECUTABLE))
+ {
+ return false;
+ }
+
+ // If the target will not be installed we do not need to change its
+ // rpath.
+ if(!this->Target->GetHaveInstallRule())
+ {
+ return false;
+ }
+
+ // Skip chrpath if skipping rpath altogether.
+ if(this->Makefile->IsOn("CMAKE_SKIP_RPATH"))
+ {
+ return false;
+ }
+
+ // Skip chrpath if it does not need to be changed at install time.
+ if(this->GetPropertyAsBool("BUILD_WITH_INSTALL_RPATH"))
+ {
+ return false;
+ }
+
+ // Allow the user to disable builtin chrpath explicitly.
+ if(this->Makefile->IsOn("CMAKE_NO_BUILTIN_CHRPATH"))
+ {
+ return false;
+ }
+
+ if(this->Makefile->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME"))
+ {
+ return true;
+ }
+
+#if defined(CMAKE_USE_ELF_PARSER)
+ // Enable if the rpath flag uses a separator and the target uses ELF
+ // binaries.
+ std::string ll = this->GetLinkerLanguage(config);
+ if(!ll.empty())
+ {
+ std::string sepVar = "CMAKE_SHARED_LIBRARY_RUNTIME_";
+ sepVar += ll;
+ sepVar += "_FLAG_SEP";
+ const char* sep = this->Makefile->GetDefinition(sepVar);
+ if(sep && *sep)
+ {
+ // TODO: Add ELF check to ABI detection and get rid of
+ // CMAKE_EXECUTABLE_FORMAT.
+ if(const char* fmt =
+ this->Makefile->GetDefinition("CMAKE_EXECUTABLE_FORMAT"))
+ {
+ return strcmp(fmt, "ELF") == 0;
+ }
+ }
+ }
+#endif
+ static_cast<void>(config);
+ return false;
+}
+
+
+//----------------------------------------------------------------------------
+std::string cmGeneratorTarget::GetSOName(const std::string& config) const
+{
+ if(this->Target->IsImported())
+ {
+ // Lookup the imported soname.
+ if(cmTarget::ImportInfo const* info = this->Target->GetImportInfo(config))
+ {
+ if(info->NoSOName)
+ {
+ // The imported library has no builtin soname so the name
+ // searched at runtime will be just the filename.
+ return cmSystemTools::GetFilenameName(info->Location);
+ }
+ else
+ {
+ // Use the soname given if any.
+ if(info->SOName.find("@rpath/") == 0)
+ {
+ return info->SOName.substr(6);
+ }
+ return info->SOName;
+ }
+ }
+ else
+ {
+ return "";
+ }
+ }
+ else
+ {
+ // Compute the soname that will be built.
+ std::string name;
+ std::string soName;
+ std::string realName;
+ std::string impName;
+ std::string pdbName;
+ this->GetLibraryNames(name, soName, realName,
+ impName, pdbName, config);
+ return soName;
+ }
+}
+
+
+//----------------------------------------------------------------------------
+std::string
+cmGeneratorTarget::GetAppBundleDirectory(const std::string& config,
+ bool contentOnly) const
+{
+ std::string fpath = this->GetFullName(config, false);
+ fpath += ".app/Contents";
+ if(!contentOnly)
+ fpath += "/MacOS";
+ return fpath;
+}
+
+//----------------------------------------------------------------------------
+bool cmGeneratorTarget::IsBundleOnApple() const
+{
+ return this->Target->IsFrameworkOnApple()
+ || this->Target->IsAppBundleOnApple()
+ || this->Target->IsCFBundleOnApple();
+}
+
+//----------------------------------------------------------------------------
+std::string cmGeneratorTarget::GetCFBundleDirectory(const std::string& config,
+ bool contentOnly) const
+{
+ std::string fpath;
+ fpath += this->GetOutputName(config, false);
+ fpath += ".";
+ const char *ext = this->Target->GetProperty("BUNDLE_EXTENSION");
+ if (!ext)
+ {
+ if (this->Target->IsXCTestOnApple())
+ {
+ ext = "xctest";
+ }
+ else
+ {
+ ext = "bundle";
+ }
+ }
+ fpath += ext;
+ fpath += "/Contents";
+ if(!contentOnly)
+ fpath += "/MacOS";
+ return fpath;
+}
+
+//----------------------------------------------------------------------------
+std::string
+cmGeneratorTarget::GetFrameworkDirectory(const std::string& config,
+ bool rootDir) const
+{
+ std::string fpath;
+ fpath += this->GetOutputName(config, false);
+ fpath += ".framework";
+ if(!rootDir)
+ {
+ fpath += "/Versions/";
+ fpath += this->Target->GetFrameworkVersion();
+ }
+ return fpath;
+}
+
+//----------------------------------------------------------------------------
+std::string
+cmGeneratorTarget::GetFullName(const std::string& config, bool implib) const
+{
+ if(this->Target->IsImported())
+ {
+ return this->Target->GetFullNameImported(config, implib);
+ }
+ else
+ {
+ return this->GetFullNameInternal(config, implib);
+ }
+}
+
+//----------------------------------------------------------------------------
+std::string
+cmGeneratorTarget::GetInstallNameDirForBuildTree(
+ const std::string& config) const
+{
+ // If building directly for installation then the build tree install_name
+ // is the same as the install tree.
+ if(this->GetPropertyAsBool("BUILD_WITH_INSTALL_RPATH"))
+ {
+ return this->GetInstallNameDirForInstallTree();
+ }
+
+ // Use the build tree directory for the target.
+ if(this->Makefile->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME") &&
+ !this->Makefile->IsOn("CMAKE_SKIP_RPATH") &&
+ !this->GetPropertyAsBool("SKIP_BUILD_RPATH"))
+ {
+ std::string dir;
+ if(this->Target->MacOSXRpathInstallNameDirDefault())
+ {
+ dir = "@rpath";
+ }
+ else
+ {
+ dir = this->Target->GetDirectory(config);
+ }
+ dir += "/";
+ return dir;
+ }
+ else
+ {
+ return "";
+ }
+}
+
+//----------------------------------------------------------------------------
+std::string cmGeneratorTarget::GetInstallNameDirForInstallTree() const
+{
+ if(this->Makefile->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME"))
+ {
+ std::string dir;
+ const char* install_name_dir = this->GetProperty("INSTALL_NAME_DIR");
+
+ if(!this->Makefile->IsOn("CMAKE_SKIP_RPATH") &&
+ !this->Makefile->IsOn("CMAKE_SKIP_INSTALL_RPATH"))
+ {
+ if(install_name_dir && *install_name_dir)
+ {
+ dir = install_name_dir;
+ dir += "/";
+ }
+ }
+ if(!install_name_dir)
+ {
+ if(this->Target->MacOSXRpathInstallNameDirDefault())
+ {
+ dir = "@rpath/";
+ }
+ }
+ return dir;
+ }
+ else
+ {
+ return "";
+ }
+}
+
+//----------------------------------------------------------------------------
+class cmTargetCollectLinkLanguages
+{
+public:
+ cmTargetCollectLinkLanguages(cmGeneratorTarget const* target,
+ const std::string& config,
+ UNORDERED_SET<std::string>& languages,
+ cmTarget const* head):
+ Config(config), Languages(languages), HeadTarget(head),
+ Makefile(target->Target->GetMakefile()), Target(target)
+ { this->Visited.insert(target->Target); }
+
+ void Visit(cmLinkItem const& item)
+ {
+ if(!item.Target)
+ {
+ if(item.find("::") != std::string::npos)
+ {
+ bool noMessage = false;
+ cmake::MessageType messageType = cmake::FATAL_ERROR;
+ std::stringstream e;
+ switch(this->Makefile->GetPolicyStatus(cmPolicies::CMP0028))
+ {
+ case cmPolicies::WARN:
+ {
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0028) << "\n";
+ messageType = cmake::AUTHOR_WARNING;
+ }
+ break;
+ case cmPolicies::OLD:
+ noMessage = true;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::NEW:
+ // Issue the fatal message.
+ break;
+ }
+
+ if(!noMessage)
+ {
+ e << "Target \"" << this->Target->GetName()
+ << "\" links to target \"" << item
+ << "\" but the target was not found. Perhaps a find_package() "
+ "call is missing for an IMPORTED target, or an ALIAS target is "
+ "missing?";
+ this->Makefile->GetCMakeInstance()->IssueMessage(
+ messageType, e.str(), this->Target->Target->GetBacktrace());
+ }
+ }
+ return;
+ }
+ if(!this->Visited.insert(item.Target).second)
+ {
+ return;
+ }
+
+ cmTarget::LinkInterface const* iface =
+ item.Target->GetLinkInterface(this->Config, this->HeadTarget);
+ if(!iface) { return; }
+
+ for(std::vector<std::string>::const_iterator
+ li = iface->Languages.begin(); li != iface->Languages.end(); ++li)
+ {
+ this->Languages.insert(*li);
+ }
+
+ for(std::vector<cmLinkItem>::const_iterator
+ li = iface->Libraries.begin(); li != iface->Libraries.end(); ++li)
+ {
+ this->Visit(*li);
+ }
+ }
+private:
+ std::string Config;
+ UNORDERED_SET<std::string>& Languages;
+ cmTarget const* HeadTarget;
+ cmMakefile* Makefile;
+ const cmGeneratorTarget* Target;
+ std::set<cmTarget const*> Visited;
+};
+
+//----------------------------------------------------------------------------
+cmGeneratorTarget::LinkClosure const*
+cmGeneratorTarget::GetLinkClosure(const std::string& config) const
+{
+ std::string key(cmSystemTools::UpperCase(config));
+ LinkClosureMapType::iterator
+ i = this->LinkClosureMap.find(key);
+ if(i == this->LinkClosureMap.end())
+ {
+ LinkClosure lc;
+ this->ComputeLinkClosure(config, lc);
+ LinkClosureMapType::value_type entry(key, lc);
+ i = this->LinkClosureMap.insert(entry).first;
+ }
+ return &i->second;
+}
+
+//----------------------------------------------------------------------------
+class cmTargetSelectLinker
+{
+ int Preference;
+ cmGeneratorTarget const* Target;
+ cmMakefile* Makefile;
+ cmGlobalGenerator* GG;
+ std::set<std::string> Preferred;
+public:
+ cmTargetSelectLinker(cmGeneratorTarget const* target)
+ : Preference(0), Target(target)
+ {
+ this->Makefile = this->Target->Makefile;
+ this->GG = this->Makefile->GetGlobalGenerator();
+ }
+ void Consider(const char* lang)
+ {
+ int preference = this->GG->GetLinkerPreference(lang);
+ if(preference > this->Preference)
+ {
+ this->Preference = preference;
+ this->Preferred.clear();
+ }
+ if(preference == this->Preference)
+ {
+ this->Preferred.insert(lang);
+ }
+ }
+ std::string Choose()
+ {
+ if(this->Preferred.empty())
+ {
+ return "";
+ }
+ else if(this->Preferred.size() > 1)
+ {
+ std::stringstream e;
+ e << "Target " << this->Target->GetName()
+ << " contains multiple languages with the highest linker preference"
+ << " (" << this->Preference << "):\n";
+ for(std::set<std::string>::const_iterator
+ li = this->Preferred.begin(); li != this->Preferred.end(); ++li)
+ {
+ e << " " << *li << "\n";
+ }
+ e << "Set the LINKER_LANGUAGE property for this target.";
+ cmake* cm = this->Makefile->GetCMakeInstance();
+ cm->IssueMessage(cmake::FATAL_ERROR, e.str(),
+ this->Target->Target->GetBacktrace());
+ }
+ return *this->Preferred.begin();
+ }
+};
+
+//----------------------------------------------------------------------------
+void cmGeneratorTarget::ComputeLinkClosure(const std::string& config,
+ LinkClosure& lc) const
+{
+ // Get languages built in this target.
+ UNORDERED_SET<std::string> languages;
+ cmTarget::LinkImplementation const* impl =
+ this->Target->GetLinkImplementation(config);
+ assert(impl);
+ for(std::vector<std::string>::const_iterator li = impl->Languages.begin();
+ li != impl->Languages.end(); ++li)
+ {
+ languages.insert(*li);
+ }
+
+ // Add interface languages from linked targets.
+ cmTargetCollectLinkLanguages cll(this, config, languages, this->Target);
+ for(std::vector<cmLinkImplItem>::const_iterator li = impl->Libraries.begin();
+ li != impl->Libraries.end(); ++li)
+ {
+ cll.Visit(*li);
+ }
+
+ // Store the transitive closure of languages.
+ for(UNORDERED_SET<std::string>::const_iterator li = languages.begin();
+ li != languages.end(); ++li)
+ {
+ lc.Languages.push_back(*li);
+ }
+
+ // Choose the language whose linker should be used.
+ if(this->GetProperty("HAS_CXX"))
+ {
+ lc.LinkerLanguage = "CXX";
+ }
+ else if(const char* linkerLang = this->GetProperty("LINKER_LANGUAGE"))
+ {
+ lc.LinkerLanguage = linkerLang;
+ }
+ else
+ {
+ // Find the language with the highest preference value.
+ cmTargetSelectLinker tsl(this);
+
+ // First select from the languages compiled directly in this target.
+ for(std::vector<std::string>::const_iterator li = impl->Languages.begin();
+ li != impl->Languages.end(); ++li)
+ {
+ tsl.Consider(li->c_str());
+ }
+
+ // Now consider languages that propagate from linked targets.
+ for(UNORDERED_SET<std::string>::const_iterator sit = languages.begin();
+ sit != languages.end(); ++sit)
+ {
+ std::string propagates = "CMAKE_"+*sit+"_LINKER_PREFERENCE_PROPAGATES";
+ if(this->Makefile->IsOn(propagates))
+ {
+ tsl.Consider(sit->c_str());
+ }
+ }
+
+ lc.LinkerLanguage = tsl.Choose();
+ }
+}
+
+//----------------------------------------------------------------------------
+void cmGeneratorTarget::GetFullNameComponents(std::string& prefix,
+ std::string& base,
+ std::string& suffix,
+ const std::string& config,
+ bool implib) const
+{
+ this->GetFullNameInternal(config, implib, prefix, base, suffix);
+}
+
+//----------------------------------------------------------------------------
+std::string
+cmGeneratorTarget::BuildMacContentDirectory(const std::string& base,
+ const std::string& config,
+ bool contentOnly) const
+{
+ std::string fpath = base;
+ if(this->Target->IsAppBundleOnApple())
+ {
+ fpath += this->GetAppBundleDirectory(config, contentOnly);
+ }
+ if(this->Target->IsFrameworkOnApple())
+ {
+ fpath += this->GetFrameworkDirectory(config, contentOnly);
+ }
+ if(this->Target->IsCFBundleOnApple())
+ {
+ fpath += this->GetCFBundleDirectory(config, contentOnly);
+ }
+ return fpath;
+}
+
+//----------------------------------------------------------------------------
+std::string
+cmGeneratorTarget::GetMacContentDirectory(const std::string& config,
+ bool implib) const
+{
+ // Start with the output directory for the target.
+ std::string fpath = this->Target->GetDirectory(config, implib);
+ fpath += "/";
+ bool contentOnly = true;
+ if(this->Target->IsFrameworkOnApple())
+ {
+ // additional files with a framework go into the version specific
+ // directory
+ contentOnly = false;
+ }
+ fpath = this->BuildMacContentDirectory(fpath, config, contentOnly);
+ return fpath;
+}
+
+
+//----------------------------------------------------------------------------
+cmGeneratorTarget::CompileInfo const* cmGeneratorTarget::GetCompileInfo(
+ const std::string& config) const
+{
+ // There is no compile information for imported targets.
+ if(this->IsImported())
+ {
+ return 0;
+ }
+
+ if(this->GetType() > cmTarget::OBJECT_LIBRARY)
+ {
+ std::string msg = "cmTarget::GetCompileInfo called for ";
+ msg += this->GetName();
+ msg += " which has type ";
+ msg += cmTarget::GetTargetTypeName(this->Target->GetType());
+ this->Makefile->IssueMessage(cmake::INTERNAL_ERROR, msg);
+ return 0;
+ }
+
+ // Lookup/compute/cache the compile information for this configuration.
+ std::string config_upper;
+ if(!config.empty())
+ {
+ config_upper = cmSystemTools::UpperCase(config);
+ }
+ CompileInfoMapType::const_iterator i =
+ this->CompileInfoMap.find(config_upper);
+ if(i == this->CompileInfoMap.end())
+ {
+ CompileInfo info;
+ this->Target
+ ->ComputePDBOutputDir("COMPILE_PDB", config, info.CompilePdbDir);
+ CompileInfoMapType::value_type entry(config_upper, info);
+ i = this->CompileInfoMap.insert(entry).first;
+ }
+ return &i->second;
+}
+
+//----------------------------------------------------------------------------
+std::string
cmGeneratorTarget::GetModuleDefinitionFile(const std::string& config) const
{
std::string data;
@@ -700,6 +1448,79 @@ cmGeneratorTarget::UseObjectLibraries(std::vector<std::string>& objs,
}
//----------------------------------------------------------------------------
+void cmGeneratorTarget::GetAutoUicOptions(std::vector<std::string> &result,
+ const std::string& config) const
+{
+ const char *prop
+ = this->GetLinkInterfaceDependentStringProperty("AUTOUIC_OPTIONS",
+ config);
+ if (!prop)
+ {
+ return;
+ }
+ cmGeneratorExpression ge;
+
+ cmGeneratorExpressionDAGChecker dagChecker(
+ this->GetName(),
+ "AUTOUIC_OPTIONS", 0, 0);
+ cmSystemTools::ExpandListArgument(ge.Parse(prop)
+ ->Evaluate(this->Makefile,
+ config,
+ false,
+ this->Target,
+ &dagChecker),
+ result);
+}
+
+//----------------------------------------------------------------------------
+void processILibs(const std::string& config,
+ cmTarget const* headTarget,
+ cmLinkItem const& item,
+ std::vector<cmTarget const*>& tgts,
+ std::set<cmTarget const*>& emitted)
+{
+ if (item.Target && emitted.insert(item.Target).second)
+ {
+ tgts.push_back(item.Target);
+ if(cmTarget::LinkInterfaceLibraries const* iface =
+ item.Target->GetLinkInterfaceLibraries(config, headTarget, true))
+ {
+ for(std::vector<cmLinkItem>::const_iterator
+ it = iface->Libraries.begin();
+ it != iface->Libraries.end(); ++it)
+ {
+ processILibs(config, headTarget, *it, tgts, emitted);
+ }
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+const std::vector<const cmTarget*>&
+cmGeneratorTarget::GetLinkImplementationClosure(
+ const std::string& config) const
+{
+ LinkImplClosure& tgts =
+ this->LinkImplClosureMap[config];
+ if(!tgts.Done)
+ {
+ tgts.Done = true;
+ std::set<cmTarget const*> emitted;
+
+ cmLinkImplementationLibraries const* impl
+ = this->Target->GetLinkImplementationLibraries(config);
+
+ for(std::vector<cmLinkImplItem>::const_iterator
+ it = impl->Libraries.begin();
+ it != impl->Libraries.end(); ++it)
+ {
+ processILibs(config, this->Target, *it, tgts , emitted);
+ }
+ }
+ return tgts;
+}
+
+//----------------------------------------------------------------------------
class cmTargetTraceDependencies
{
public:
@@ -736,7 +1557,7 @@ cmTargetTraceDependencies
{
// Convenience.
this->Makefile = this->Target->GetMakefile();
- this->GlobalGenerator = this->Makefile->GetGlobalGenerator();
+ this->GlobalGenerator = target->GetLocalGenerator()->GetGlobalGenerator();
this->CurrentEntry = 0;
// Queue all the source files already specified for the target.
@@ -1044,6 +1865,16 @@ void cmGeneratorTarget::TraceDependencies()
tracer.Trace();
}
+std::string
+cmGeneratorTarget::GetCompilePDBDirectory(const std::string& config) const
+{
+ if(CompileInfo const* info = this->GetCompileInfo(config))
+ {
+ return info->CompilePdbDir;
+ }
+ return "";
+}
+
//----------------------------------------------------------------------------
void cmGeneratorTarget::GetAppleArchs(const std::string& config,
std::vector<std::string>& archVec) const
@@ -1114,8 +1945,7 @@ void cmGeneratorTarget::GenerateTargetManifest(
{
return;
}
- cmMakefile* mf = this->Target->GetMakefile();
- cmGlobalGenerator* gg = mf->GetGlobalGenerator();
+ cmGlobalGenerator* gg = this->LocalGenerator->GetGlobalGenerator();
// Get the names.
std::string name;
@@ -1125,14 +1955,13 @@ void cmGeneratorTarget::GenerateTargetManifest(
std::string pdbName;
if(this->GetType() == cmTarget::EXECUTABLE)
{
- this->Target->GetExecutableNames(name, realName, impName, pdbName,
- config);
+ this->GetExecutableNames(name, realName, impName, pdbName, config);
}
else if(this->GetType() == cmTarget::STATIC_LIBRARY ||
this->GetType() == cmTarget::SHARED_LIBRARY ||
this->GetType() == cmTarget::MODULE_LIBRARY)
{
- this->Target->GetLibraryNames(name, soName, realName, impName, pdbName,
+ this->GetLibraryNames(name, soName, realName, impName, pdbName,
config);
}
else
@@ -1150,35 +1979,35 @@ void cmGeneratorTarget::GenerateTargetManifest(
f = dir;
f += "/";
f += name;
- gg->AddToManifest(config, f);
+ gg->AddToManifest(f);
}
if(!soName.empty())
{
f = dir;
f += "/";
f += soName;
- gg->AddToManifest(config, f);
+ gg->AddToManifest(f);
}
if(!realName.empty())
{
f = dir;
f += "/";
f += realName;
- gg->AddToManifest(config, f);
+ gg->AddToManifest(f);
}
if(!pdbName.empty())
{
f = dir;
f += "/";
f += pdbName;
- gg->AddToManifest(config, f);
+ gg->AddToManifest(f);
}
if(!impName.empty())
{
f = this->Target->GetDirectory(config, true);
f += "/";
f += impName;
- gg->AddToManifest(config, f);
+ gg->AddToManifest(f);
}
}
@@ -1204,14 +2033,14 @@ std::string cmGeneratorTarget::NormalGetFullPath(const std::string& config,
fpath += "/";
if(this->Target->IsAppBundleOnApple())
{
- fpath = this->Target->BuildMacContentDirectory(fpath, config, false);
+ fpath = this->BuildMacContentDirectory(fpath, config, false);
fpath += "/";
}
// Add the full name of the target.
if(implib)
{
- fpath += this->Target->GetFullName(config, true);
+ fpath += this->GetFullName(config, true);
}
else if(realname)
{
@@ -1219,7 +2048,7 @@ std::string cmGeneratorTarget::NormalGetFullPath(const std::string& config,
}
else
{
- fpath += this->Target->GetFullName(config, false);
+ fpath += this->GetFullName(config, false);
}
return fpath;
}
@@ -1245,7 +2074,7 @@ cmGeneratorTarget::NormalGetRealName(const std::string& config) const
std::string realName;
std::string impName;
std::string pdbName;
- this->Target->GetExecutableNames(name, realName, impName, pdbName, config);
+ this->GetExecutableNames(name, realName, impName, pdbName, config);
return realName;
}
else
@@ -1256,12 +2085,344 @@ cmGeneratorTarget::NormalGetRealName(const std::string& config) const
std::string realName;
std::string impName;
std::string pdbName;
- this->Target->GetLibraryNames(name, soName, realName,
- impName, pdbName, config);
+ this->GetLibraryNames(name, soName, realName,
+ impName, pdbName, config);
return realName;
}
}
+//----------------------------------------------------------------------------
+void cmGeneratorTarget::GetLibraryNames(std::string& name,
+ std::string& soName,
+ std::string& realName,
+ std::string& impName,
+ std::string& pdbName,
+ const std::string& config) const
+{
+ // This should not be called for imported targets.
+ // TODO: Split cmTarget into a class hierarchy to get compile-time
+ // enforcement of the limited imported target API.
+ if(this->Target->IsImported())
+ {
+ std::string msg = "GetLibraryNames called on imported target: ";
+ msg += this->GetName();
+ this->LocalGenerator->IssueMessage(cmake::INTERNAL_ERROR,
+ msg);
+ return;
+ }
+
+ // Check for library version properties.
+ const char* version = this->GetProperty("VERSION");
+ const char* soversion = this->GetProperty("SOVERSION");
+ if(!this->HasSOName(config) ||
+ this->Target->IsFrameworkOnApple())
+ {
+ // Versioning is supported only for shared libraries and modules,
+ // and then only when the platform supports an soname flag.
+ version = 0;
+ soversion = 0;
+ }
+ if(version && !soversion)
+ {
+ // The soversion must be set if the library version is set. Use
+ // the library version as the soversion.
+ soversion = version;
+ }
+ if(!version && soversion)
+ {
+ // Use the soversion as the library version.
+ version = soversion;
+ }
+
+ // Get the components of the library name.
+ std::string prefix;
+ std::string base;
+ std::string suffix;
+ this->GetFullNameInternal(config, false, prefix, base, suffix);
+
+ // The library name.
+ name = prefix+base+suffix;
+
+ if(this->Target->IsFrameworkOnApple())
+ {
+ realName = prefix;
+ realName += "Versions/";
+ realName += this->Target->GetFrameworkVersion();
+ realName += "/";
+ realName += base;
+ soName = realName;
+ }
+ else
+ {
+ // The library's soname.
+ this->Target->ComputeVersionedName(soName, prefix, base, suffix,
+ name, soversion);
+
+ // The library's real name on disk.
+ this->Target->ComputeVersionedName(realName, prefix, base, suffix,
+ name, version);
+ }
+
+ // The import library name.
+ if(this->GetType() == cmTarget::SHARED_LIBRARY ||
+ this->GetType() == cmTarget::MODULE_LIBRARY)
+ {
+ impName = this->GetFullNameInternal(config, true);
+ }
+ else
+ {
+ impName = "";
+ }
+
+ // The program database file name.
+ pdbName = this->GetPDBName(config);
+}
+
+//----------------------------------------------------------------------------
+void cmGeneratorTarget::GetExecutableNames(std::string& name,
+ std::string& realName,
+ std::string& impName,
+ std::string& pdbName,
+ const std::string& config) const
+{
+ // This should not be called for imported targets.
+ // TODO: Split cmTarget into a class hierarchy to get compile-time
+ // enforcement of the limited imported target API.
+ if(this->Target->IsImported())
+ {
+ std::string msg =
+ "GetExecutableNames called on imported target: ";
+ msg += this->GetName();
+ this->LocalGenerator->IssueMessage(cmake::INTERNAL_ERROR, msg);
+ }
+
+ // This versioning is supported only for executables and then only
+ // when the platform supports symbolic links.
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ const char* version = 0;
+#else
+ // Check for executable version properties.
+ const char* version = this->GetProperty("VERSION");
+ if(this->GetType() != cmTarget::EXECUTABLE || this->Makefile->IsOn("XCODE"))
+ {
+ version = 0;
+ }
+#endif
+
+ // Get the components of the executable name.
+ std::string prefix;
+ std::string base;
+ std::string suffix;
+ this->GetFullNameInternal(config, false, prefix, base, suffix);
+
+ // The executable name.
+ name = prefix+base+suffix;
+
+ // The executable's real name on disk.
+#if defined(__CYGWIN__)
+ realName = prefix+base;
+#else
+ realName = name;
+#endif
+ if(version)
+ {
+ realName += "-";
+ realName += version;
+ }
+#if defined(__CYGWIN__)
+ realName += suffix;
+#endif
+
+ // The import library name.
+ impName = this->GetFullNameInternal(config, true);
+
+ // The program database file name.
+ pdbName = this->GetPDBName(config);
+}
+
+//----------------------------------------------------------------------------
+std::string cmGeneratorTarget::GetFullNameInternal(const std::string& config,
+ bool implib) const
+{
+ std::string prefix;
+ std::string base;
+ std::string suffix;
+ this->GetFullNameInternal(config, implib, prefix, base, suffix);
+ return prefix+base+suffix;
+}
+
+//----------------------------------------------------------------------------
+void cmGeneratorTarget::GetFullNameInternal(const std::string& config,
+ bool implib,
+ std::string& outPrefix,
+ std::string& outBase,
+ std::string& outSuffix) const
+{
+ // Use just the target name for non-main target types.
+ if(this->GetType() != cmTarget::STATIC_LIBRARY &&
+ this->GetType() != cmTarget::SHARED_LIBRARY &&
+ this->GetType() != cmTarget::MODULE_LIBRARY &&
+ this->GetType() != cmTarget::EXECUTABLE)
+ {
+ outPrefix = "";
+ outBase = this->GetName();
+ outSuffix = "";
+ return;
+ }
+
+ // Return an empty name for the import library if this platform
+ // does not support import libraries.
+ if(implib &&
+ !this->Makefile->GetDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX"))
+ {
+ outPrefix = "";
+ outBase = "";
+ outSuffix = "";
+ return;
+ }
+
+ // The implib option is only allowed for shared libraries, module
+ // libraries, and executables.
+ if(this->GetType() != cmTarget::SHARED_LIBRARY &&
+ this->GetType() != cmTarget::MODULE_LIBRARY &&
+ this->GetType() != cmTarget::EXECUTABLE)
+ {
+ implib = false;
+ }
+
+ // Compute the full name for main target types.
+ const char* targetPrefix = (implib
+ ? this->GetProperty("IMPORT_PREFIX")
+ : this->GetProperty("PREFIX"));
+ const char* targetSuffix = (implib
+ ? this->GetProperty("IMPORT_SUFFIX")
+ : this->GetProperty("SUFFIX"));
+ const char* configPostfix = 0;
+ if(!config.empty())
+ {
+ std::string configProp = cmSystemTools::UpperCase(config);
+ configProp += "_POSTFIX";
+ configPostfix = this->GetProperty(configProp);
+ // Mac application bundles and frameworks have no postfix.
+ if(configPostfix &&
+ (this->Target->IsAppBundleOnApple()
+ || this->Target->IsFrameworkOnApple()))
+ {
+ configPostfix = 0;
+ }
+ }
+ const char* prefixVar = this->Target->GetPrefixVariableInternal(implib);
+ const char* suffixVar = this->Target->GetSuffixVariableInternal(implib);
+
+ // Check for language-specific default prefix and suffix.
+ std::string ll = this->GetLinkerLanguage(config);
+ if(!ll.empty())
+ {
+ if(!targetSuffix && suffixVar && *suffixVar)
+ {
+ std::string langSuff = suffixVar + std::string("_") + ll;
+ targetSuffix = this->Makefile->GetDefinition(langSuff);
+ }
+ if(!targetPrefix && prefixVar && *prefixVar)
+ {
+ std::string langPrefix = prefixVar + std::string("_") + ll;
+ targetPrefix = this->Makefile->GetDefinition(langPrefix);
+ }
+ }
+
+ // if there is no prefix on the target use the cmake definition
+ if(!targetPrefix && prefixVar)
+ {
+ targetPrefix = this->Makefile->GetSafeDefinition(prefixVar);
+ }
+ // if there is no suffix on the target use the cmake definition
+ if(!targetSuffix && suffixVar)
+ {
+ targetSuffix = this->Makefile->GetSafeDefinition(suffixVar);
+ }
+
+ // frameworks have directory prefix but no suffix
+ std::string fw_prefix;
+ if(this->Target->IsFrameworkOnApple())
+ {
+ fw_prefix = this->GetOutputName(config, false);
+ fw_prefix += ".framework/";
+ targetPrefix = fw_prefix.c_str();
+ targetSuffix = 0;
+ }
+
+ if(this->Target->IsCFBundleOnApple())
+ {
+ fw_prefix = this->GetCFBundleDirectory(config, false);
+ fw_prefix += "/";
+ targetPrefix = fw_prefix.c_str();
+ targetSuffix = 0;
+ }
+
+ // Begin the final name with the prefix.
+ outPrefix = targetPrefix?targetPrefix:"";
+
+ // Append the target name or property-specified name.
+ outBase += this->GetOutputName(config, implib);
+
+ // Append the per-configuration postfix.
+ outBase += configPostfix?configPostfix:"";
+
+ // Name shared libraries with their version number on some platforms.
+ if(const char* soversion = this->GetProperty("SOVERSION"))
+ {
+ if(this->GetType() == cmTarget::SHARED_LIBRARY && !implib &&
+ this->Makefile->IsOn("CMAKE_SHARED_LIBRARY_NAME_WITH_VERSION"))
+ {
+ outBase += "-";
+ outBase += soversion;
+ }
+ }
+
+ // Append the suffix.
+ outSuffix = targetSuffix?targetSuffix:"";
+}
+
+
+//----------------------------------------------------------------------------
+std::string
+cmGeneratorTarget::GetLinkerLanguage(const std::string& config) const
+{
+ return this->GetLinkClosure(config)->LinkerLanguage;
+}
+
+//----------------------------------------------------------------------------
+std::string cmGeneratorTarget::GetPDBName(const std::string& config) const
+{
+ std::string prefix;
+ std::string base;
+ std::string suffix;
+ this->GetFullNameInternal(config, false, prefix, base, suffix);
+
+ std::vector<std::string> props;
+ std::string configUpper =
+ cmSystemTools::UpperCase(config);
+ if(!configUpper.empty())
+ {
+ // PDB_NAME_<CONFIG>
+ props.push_back("PDB_NAME_" + configUpper);
+ }
+
+ // PDB_NAME
+ props.push_back("PDB_NAME");
+
+ for(std::vector<std::string>::const_iterator i = props.begin();
+ i != props.end(); ++i)
+ {
+ if(const char* outName = this->GetProperty(*i))
+ {
+ base = outName;
+ break;
+ }
+ }
+ return prefix+base+".pdb";
+}
+
bool cmStrictTargetComparison::operator()(cmTarget const* t1,
cmTarget const* t2) const
{
@@ -1367,3 +2528,797 @@ void cmGeneratorTarget::ConstructSourceFileFlags() const
}
}
}
+
+//----------------------------------------------------------------------------
+const cmGeneratorTarget::CompatibleInterfacesBase&
+cmGeneratorTarget::GetCompatibleInterfaces(std::string const& config) const
+{
+ cmGeneratorTarget::CompatibleInterfaces& compat =
+ this->CompatibleInterfacesMap[config];
+ if(!compat.Done)
+ {
+ compat.Done = true;
+ compat.PropsBool.insert("POSITION_INDEPENDENT_CODE");
+ compat.PropsString.insert("AUTOUIC_OPTIONS");
+ std::vector<cmTarget const*> const& deps =
+ this->GetLinkImplementationClosure(config);
+ for(std::vector<cmTarget const*>::const_iterator li = deps.begin();
+ li != deps.end(); ++li)
+ {
+#define CM_READ_COMPATIBLE_INTERFACE(X, x) \
+ if(const char* prop = (*li)->GetProperty("COMPATIBLE_INTERFACE_" #X)) \
+ { \
+ std::vector<std::string> props; \
+ cmSystemTools::ExpandListArgument(prop, props); \
+ compat.Props##x.insert(props.begin(), props.end()); \
+ }
+ CM_READ_COMPATIBLE_INTERFACE(BOOL, Bool)
+ CM_READ_COMPATIBLE_INTERFACE(STRING, String)
+ CM_READ_COMPATIBLE_INTERFACE(NUMBER_MIN, NumberMin)
+ CM_READ_COMPATIBLE_INTERFACE(NUMBER_MAX, NumberMax)
+#undef CM_READ_COMPATIBLE_INTERFACE
+ }
+ }
+ return compat;
+}
+
+//----------------------------------------------------------------------------
+bool cmGeneratorTarget::IsLinkInterfaceDependentBoolProperty(
+ const std::string &p, const std::string& config) const
+{
+ if (this->Target->GetType() == cmTarget::OBJECT_LIBRARY
+ || this->Target->GetType() == cmTarget::INTERFACE_LIBRARY)
+ {
+ return false;
+ }
+ return this->GetCompatibleInterfaces(config).PropsBool.count(p) > 0;
+}
+
+//----------------------------------------------------------------------------
+bool cmGeneratorTarget::IsLinkInterfaceDependentStringProperty(
+ const std::string &p, const std::string& config) const
+{
+ if (this->Target->GetType() == cmTarget::OBJECT_LIBRARY
+ || this->Target->GetType() == cmTarget::INTERFACE_LIBRARY)
+ {
+ return false;
+ }
+ return this->GetCompatibleInterfaces(config).PropsString.count(p) > 0;
+}
+
+//----------------------------------------------------------------------------
+bool cmGeneratorTarget::IsLinkInterfaceDependentNumberMinProperty(
+ const std::string &p, const std::string& config) const
+{
+ if (this->Target->GetType() == cmTarget::OBJECT_LIBRARY
+ || this->Target->GetType() == cmTarget::INTERFACE_LIBRARY)
+ {
+ return false;
+ }
+ return this->GetCompatibleInterfaces(config).PropsNumberMin.count(p) > 0;
+}
+
+//----------------------------------------------------------------------------
+bool cmGeneratorTarget::IsLinkInterfaceDependentNumberMaxProperty(
+ const std::string &p, const std::string& config) const
+{
+ if (this->Target->GetType() == cmTarget::OBJECT_LIBRARY
+ || this->Target->GetType() == cmTarget::INTERFACE_LIBRARY)
+ {
+ return false;
+ }
+ return this->GetCompatibleInterfaces(config).PropsNumberMax.count(p) > 0;
+}
+
+enum CompatibleType
+{
+ BoolType,
+ StringType,
+ NumberMinType,
+ NumberMaxType
+};
+
+template<typename PropertyType>
+PropertyType getLinkInterfaceDependentProperty(cmGeneratorTarget const* tgt,
+ const std::string& prop,
+ const std::string& config,
+ CompatibleType,
+ PropertyType *);
+
+template<>
+bool getLinkInterfaceDependentProperty(cmGeneratorTarget const* tgt,
+ const std::string& prop,
+ const std::string& config,
+ CompatibleType, bool *)
+{
+ return tgt->GetLinkInterfaceDependentBoolProperty(prop, config);
+}
+
+template<>
+const char * getLinkInterfaceDependentProperty(cmGeneratorTarget const* tgt,
+ const std::string& prop,
+ const std::string& config,
+ CompatibleType t,
+ const char **)
+{
+ switch(t)
+ {
+ case BoolType:
+ assert(0 && "String compatibility check function called for boolean");
+ return 0;
+ case StringType:
+ return tgt->GetLinkInterfaceDependentStringProperty(prop, config);
+ case NumberMinType:
+ return tgt->GetLinkInterfaceDependentNumberMinProperty(prop, config);
+ case NumberMaxType:
+ return tgt->GetLinkInterfaceDependentNumberMaxProperty(prop, config);
+ }
+ assert(0 && "Unreachable!");
+ return 0;
+}
+
+//----------------------------------------------------------------------------
+template<typename PropertyType>
+void checkPropertyConsistency(cmGeneratorTarget const* depender,
+ cmTarget const* dependee,
+ const std::string& propName,
+ std::set<std::string> &emitted,
+ const std::string& config,
+ CompatibleType t,
+ PropertyType *)
+{
+ const char *prop = dependee->GetProperty(propName);
+ if (!prop)
+ {
+ return;
+ }
+
+ std::vector<std::string> props;
+ cmSystemTools::ExpandListArgument(prop, props);
+ std::string pdir =
+ dependee->GetMakefile()->GetRequiredDefinition("CMAKE_ROOT");
+ pdir += "/Help/prop_tgt/";
+
+ for(std::vector<std::string>::iterator pi = props.begin();
+ pi != props.end(); ++pi)
+ {
+ std::string pname = cmSystemTools::HelpFileName(*pi);
+ std::string pfile = pdir + pname + ".rst";
+ if(cmSystemTools::FileExists(pfile.c_str(), true))
+ {
+ std::ostringstream e;
+ e << "Target \"" << dependee->GetName() << "\" has property \""
+ << *pi << "\" listed in its " << propName << " property. "
+ "This is not allowed. Only user-defined properties may appear "
+ "listed in the " << propName << " property.";
+ depender->GetLocalGenerator()->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return;
+ }
+ if(emitted.insert(*pi).second)
+ {
+ getLinkInterfaceDependentProperty<PropertyType>(depender, *pi, config,
+ t, 0);
+ if (cmSystemTools::GetErrorOccuredFlag())
+ {
+ return;
+ }
+ }
+ }
+}
+
+static std::string intersect(const std::set<std::string> &s1,
+ const std::set<std::string> &s2)
+{
+ std::set<std::string> intersect;
+ std::set_intersection(s1.begin(),s1.end(),
+ s2.begin(),s2.end(),
+ std::inserter(intersect,intersect.begin()));
+ if (!intersect.empty())
+ {
+ return *intersect.begin();
+ }
+ return "";
+}
+
+static std::string intersect(const std::set<std::string> &s1,
+ const std::set<std::string> &s2,
+ const std::set<std::string> &s3)
+{
+ std::string result;
+ result = intersect(s1, s2);
+ if (!result.empty())
+ return result;
+ result = intersect(s1, s3);
+ if (!result.empty())
+ return result;
+ return intersect(s2, s3);
+}
+
+static std::string intersect(const std::set<std::string> &s1,
+ const std::set<std::string> &s2,
+ const std::set<std::string> &s3,
+ const std::set<std::string> &s4)
+{
+ std::string result;
+ result = intersect(s1, s2);
+ if (!result.empty())
+ return result;
+ result = intersect(s1, s3);
+ if (!result.empty())
+ return result;
+ result = intersect(s1, s4);
+ if (!result.empty())
+ return result;
+ return intersect(s2, s3, s4);
+}
+
+//----------------------------------------------------------------------------
+void cmGeneratorTarget::CheckPropertyCompatibility(
+ cmComputeLinkInformation *info, const std::string& config) const
+{
+ const cmComputeLinkInformation::ItemVector &deps = info->GetItems();
+
+ std::set<std::string> emittedBools;
+ static std::string strBool = "COMPATIBLE_INTERFACE_BOOL";
+ std::set<std::string> emittedStrings;
+ static std::string strString = "COMPATIBLE_INTERFACE_STRING";
+ std::set<std::string> emittedMinNumbers;
+ static std::string strNumMin = "COMPATIBLE_INTERFACE_NUMBER_MIN";
+ std::set<std::string> emittedMaxNumbers;
+ static std::string strNumMax = "COMPATIBLE_INTERFACE_NUMBER_MAX";
+
+ for(cmComputeLinkInformation::ItemVector::const_iterator li =
+ deps.begin(); li != deps.end(); ++li)
+ {
+ if (!li->Target)
+ {
+ continue;
+ }
+
+ checkPropertyConsistency<bool>(this, li->Target,
+ strBool,
+ emittedBools, config, BoolType, 0);
+ if (cmSystemTools::GetErrorOccuredFlag())
+ {
+ return;
+ }
+ checkPropertyConsistency<const char *>(this, li->Target,
+ strString,
+ emittedStrings, config,
+ StringType, 0);
+ if (cmSystemTools::GetErrorOccuredFlag())
+ {
+ return;
+ }
+ checkPropertyConsistency<const char *>(this, li->Target,
+ strNumMin,
+ emittedMinNumbers, config,
+ NumberMinType, 0);
+ if (cmSystemTools::GetErrorOccuredFlag())
+ {
+ return;
+ }
+ checkPropertyConsistency<const char *>(this, li->Target,
+ strNumMax,
+ emittedMaxNumbers, config,
+ NumberMaxType, 0);
+ if (cmSystemTools::GetErrorOccuredFlag())
+ {
+ return;
+ }
+ }
+
+ std::string prop = intersect(emittedBools,
+ emittedStrings,
+ emittedMinNumbers,
+ emittedMaxNumbers);
+
+ if (!prop.empty())
+ {
+ // Use a sorted std::vector to keep the error message sorted.
+ std::vector<std::string> props;
+ std::set<std::string>::const_iterator i = emittedBools.find(prop);
+ if (i != emittedBools.end())
+ {
+ props.push_back(strBool);
+ }
+ i = emittedStrings.find(prop);
+ if (i != emittedStrings.end())
+ {
+ props.push_back(strString);
+ }
+ i = emittedMinNumbers.find(prop);
+ if (i != emittedMinNumbers.end())
+ {
+ props.push_back(strNumMin);
+ }
+ i = emittedMaxNumbers.find(prop);
+ if (i != emittedMaxNumbers.end())
+ {
+ props.push_back(strNumMax);
+ }
+ std::sort(props.begin(), props.end());
+
+ std::string propsString = cmJoin(cmMakeRange(props).retreat(1), ", ");
+ propsString += " and the " + props.back();
+
+ std::ostringstream e;
+ e << "Property \"" << prop << "\" appears in both the "
+ << propsString <<
+ " property in the dependencies of target \"" << this->GetName() <<
+ "\". This is not allowed. A property may only require compatibility "
+ "in a boolean interpretation, a numeric minimum, a numeric maximum or a "
+ "string interpretation, but not a mixture.";
+ this->LocalGenerator->IssueMessage(cmake::FATAL_ERROR, e.str());
+ }
+}
+
+//----------------------------------------------------------------------------
+std::string compatibilityType(CompatibleType t)
+{
+ switch(t)
+ {
+ case BoolType:
+ return "Boolean compatibility";
+ case StringType:
+ return "String compatibility";
+ case NumberMaxType:
+ return "Numeric maximum compatibility";
+ case NumberMinType:
+ return "Numeric minimum compatibility";
+ }
+ assert(0 && "Unreachable!");
+ return "";
+}
+
+//----------------------------------------------------------------------------
+std::string compatibilityAgree(CompatibleType t, bool dominant)
+{
+ switch(t)
+ {
+ case BoolType:
+ case StringType:
+ return dominant ? "(Disagree)\n" : "(Agree)\n";
+ case NumberMaxType:
+ case NumberMinType:
+ return dominant ? "(Dominant)\n" : "(Ignored)\n";
+ }
+ assert(0 && "Unreachable!");
+ return "";
+}
+
+//----------------------------------------------------------------------------
+template<typename PropertyType>
+PropertyType getTypedProperty(cmTarget const* tgt, const std::string& prop);
+
+//----------------------------------------------------------------------------
+template<>
+bool getTypedProperty<bool>(cmTarget const* tgt, const std::string& prop)
+{
+ return tgt->GetPropertyAsBool(prop);
+}
+
+//----------------------------------------------------------------------------
+template<>
+const char *getTypedProperty<const char *>(cmTarget const* tgt,
+ const std::string& prop)
+{
+ return tgt->GetProperty(prop);
+}
+
+template<typename PropertyType>
+std::string valueAsString(PropertyType);
+template<>
+std::string valueAsString<bool>(bool value)
+{
+ return value ? "TRUE" : "FALSE";
+}
+template<>
+std::string valueAsString<const char*>(const char* value)
+{
+ return value ? value : "(unset)";
+}
+
+template<typename PropertyType>
+PropertyType impliedValue(PropertyType);
+template<>
+bool impliedValue<bool>(bool)
+{
+ return false;
+}
+template<>
+const char* impliedValue<const char*>(const char*)
+{
+ return "";
+}
+
+//----------------------------------------------------------------------------
+template<typename PropertyType>
+std::pair<bool, PropertyType> consistentProperty(PropertyType lhs,
+ PropertyType rhs,
+ CompatibleType t);
+
+//----------------------------------------------------------------------------
+template<>
+std::pair<bool, bool> consistentProperty(bool lhs, bool rhs,
+ CompatibleType)
+{
+ return std::make_pair(lhs == rhs, lhs);
+}
+
+//----------------------------------------------------------------------------
+std::pair<bool, const char*> consistentStringProperty(const char *lhs,
+ const char *rhs)
+{
+ const bool b = strcmp(lhs, rhs) == 0;
+ return std::make_pair(b, b ? lhs : 0);
+}
+
+//----------------------------------------------------------------------------
+std::pair<bool, const char*> consistentNumberProperty(const char *lhs,
+ const char *rhs,
+ CompatibleType t)
+{
+ char *pEnd;
+
+ const char* const null_ptr = 0;
+
+ long lnum = strtol(lhs, &pEnd, 0);
+ if (pEnd == lhs || *pEnd != '\0' || errno == ERANGE)
+ {
+ return std::pair<bool, const char*>(false, null_ptr);
+ }
+
+ long rnum = strtol(rhs, &pEnd, 0);
+ if (pEnd == rhs || *pEnd != '\0' || errno == ERANGE)
+ {
+ return std::pair<bool, const char*>(false, null_ptr);
+ }
+
+ if (t == NumberMaxType)
+ {
+ return std::make_pair(true, std::max(lnum, rnum) == lnum ? lhs : rhs);
+ }
+ else
+ {
+ return std::make_pair(true, std::min(lnum, rnum) == lnum ? lhs : rhs);
+ }
+}
+
+//----------------------------------------------------------------------------
+template<>
+std::pair<bool, const char*> consistentProperty(const char *lhs,
+ const char *rhs,
+ CompatibleType t)
+{
+ if (!lhs && !rhs)
+ {
+ return std::make_pair(true, lhs);
+ }
+ if (!lhs)
+ {
+ return std::make_pair(true, rhs);
+ }
+ if (!rhs)
+ {
+ return std::make_pair(true, lhs);
+ }
+
+ const char* const null_ptr = 0;
+
+ switch(t)
+ {
+ case BoolType:
+ assert(0 && "consistentProperty for strings called with BoolType");
+ return std::pair<bool, const char*>(false, null_ptr);
+ case StringType:
+ return consistentStringProperty(lhs, rhs);
+ case NumberMinType:
+ case NumberMaxType:
+ return consistentNumberProperty(lhs, rhs, t);
+ }
+ assert(0 && "Unreachable!");
+ return std::pair<bool, const char*>(false, null_ptr);
+}
+
+//----------------------------------------------------------------------------
+template<typename PropertyType>
+PropertyType checkInterfacePropertyCompatibility(cmGeneratorTarget const* tgt,
+ const std::string &p,
+ const std::string& config,
+ const char *defaultValue,
+ CompatibleType t,
+ PropertyType *)
+{
+ PropertyType propContent = getTypedProperty<PropertyType>(tgt->Target, p);
+ const bool explicitlySet = tgt->Target->GetProperties()
+ .find(p)
+ != tgt->Target->GetProperties().end();
+ const bool impliedByUse =
+ tgt->Target->IsNullImpliedByLinkLibraries(p);
+ assert((impliedByUse ^ explicitlySet)
+ || (!impliedByUse && !explicitlySet));
+
+ std::vector<cmTarget const*> const& deps =
+ tgt->GetLinkImplementationClosure(config);
+
+ if(deps.empty())
+ {
+ return propContent;
+ }
+ bool propInitialized = explicitlySet;
+
+ std::string report = " * Target \"";
+ report += tgt->GetName();
+ if (explicitlySet)
+ {
+ report += "\" has property content \"";
+ report += valueAsString<PropertyType>(propContent);
+ report += "\"\n";
+ }
+ else if (impliedByUse)
+ {
+ report += "\" property is implied by use.\n";
+ }
+ else
+ {
+ report += "\" property not set.\n";
+ }
+
+ std::string interfaceProperty = "INTERFACE_" + p;
+ for(std::vector<cmTarget const*>::const_iterator li =
+ deps.begin();
+ li != deps.end(); ++li)
+ {
+ // An error should be reported if one dependency
+ // has INTERFACE_POSITION_INDEPENDENT_CODE ON and the other
+ // has INTERFACE_POSITION_INDEPENDENT_CODE OFF, or if the
+ // target itself has a POSITION_INDEPENDENT_CODE which disagrees
+ // with a dependency.
+
+ cmTarget const* theTarget = *li;
+
+ const bool ifaceIsSet = theTarget->GetProperties()
+ .find(interfaceProperty)
+ != theTarget->GetProperties().end();
+ PropertyType ifacePropContent =
+ getTypedProperty<PropertyType>(theTarget,
+ interfaceProperty);
+
+ std::string reportEntry;
+ if (ifaceIsSet)
+ {
+ reportEntry += " * Target \"";
+ reportEntry += theTarget->GetName();
+ reportEntry += "\" property value \"";
+ reportEntry += valueAsString<PropertyType>(ifacePropContent);
+ reportEntry += "\" ";
+ }
+
+ if (explicitlySet)
+ {
+ if (ifaceIsSet)
+ {
+ std::pair<bool, PropertyType> consistent =
+ consistentProperty(propContent,
+ ifacePropContent, t);
+ report += reportEntry;
+ report += compatibilityAgree(t, propContent != consistent.second);
+ if (!consistent.first)
+ {
+ std::ostringstream e;
+ e << "Property " << p << " on target \""
+ << tgt->GetName() << "\" does\nnot match the "
+ "INTERFACE_" << p << " property requirement\nof "
+ "dependency \"" << theTarget->GetName() << "\".\n";
+ cmSystemTools::Error(e.str().c_str());
+ break;
+ }
+ else
+ {
+ propContent = consistent.second;
+ continue;
+ }
+ }
+ else
+ {
+ // Explicitly set on target and not set in iface. Can't disagree.
+ continue;
+ }
+ }
+ else if (impliedByUse)
+ {
+ propContent = impliedValue<PropertyType>(propContent);
+
+ if (ifaceIsSet)
+ {
+ std::pair<bool, PropertyType> consistent =
+ consistentProperty(propContent,
+ ifacePropContent, t);
+ report += reportEntry;
+ report += compatibilityAgree(t, propContent != consistent.second);
+ if (!consistent.first)
+ {
+ std::ostringstream e;
+ e << "Property " << p << " on target \""
+ << tgt->GetName() << "\" is\nimplied to be " << defaultValue
+ << " because it was used to determine the link libraries\n"
+ "already. The INTERFACE_" << p << " property on\ndependency \""
+ << theTarget->GetName() << "\" is in conflict.\n";
+ cmSystemTools::Error(e.str().c_str());
+ break;
+ }
+ else
+ {
+ propContent = consistent.second;
+ continue;
+ }
+ }
+ else
+ {
+ // Implicitly set on target and not set in iface. Can't disagree.
+ continue;
+ }
+ }
+ else
+ {
+ if (ifaceIsSet)
+ {
+ if (propInitialized)
+ {
+ std::pair<bool, PropertyType> consistent =
+ consistentProperty(propContent,
+ ifacePropContent, t);
+ report += reportEntry;
+ report += compatibilityAgree(t, propContent != consistent.second);
+ if (!consistent.first)
+ {
+ std::ostringstream e;
+ e << "The INTERFACE_" << p << " property of \""
+ << theTarget->GetName() << "\" does\nnot agree with the value "
+ "of " << p << " already determined\nfor \""
+ << tgt->GetName() << "\".\n";
+ cmSystemTools::Error(e.str().c_str());
+ break;
+ }
+ else
+ {
+ propContent = consistent.second;
+ continue;
+ }
+ }
+ else
+ {
+ report += reportEntry + "(Interface set)\n";
+ propContent = ifacePropContent;
+ propInitialized = true;
+ }
+ }
+ else
+ {
+ // Not set. Nothing to agree on.
+ continue;
+ }
+ }
+ }
+
+ tgt->ReportPropertyOrigin(p, valueAsString<PropertyType>(propContent),
+ report, compatibilityType(t));
+ return propContent;
+}
+
+//----------------------------------------------------------------------------
+bool cmGeneratorTarget::GetLinkInterfaceDependentBoolProperty(
+ const std::string &p, const std::string& config) const
+{
+ return checkInterfacePropertyCompatibility<bool>(this, p, config,
+ "FALSE",
+ BoolType, 0);
+}
+
+//----------------------------------------------------------------------------
+const char* cmGeneratorTarget::GetLinkInterfaceDependentStringProperty(
+ const std::string &p,
+ const std::string& config) const
+{
+ return checkInterfacePropertyCompatibility<const char *>(this,
+ p,
+ config,
+ "empty",
+ StringType, 0);
+}
+
+//----------------------------------------------------------------------------
+const char * cmGeneratorTarget::GetLinkInterfaceDependentNumberMinProperty(
+ const std::string &p,
+ const std::string& config) const
+{
+ return checkInterfacePropertyCompatibility<const char *>(this,
+ p,
+ config,
+ "empty",
+ NumberMinType, 0);
+}
+
+//----------------------------------------------------------------------------
+const char * cmGeneratorTarget::GetLinkInterfaceDependentNumberMaxProperty(
+ const std::string &p,
+ const std::string& config) const
+{
+ return checkInterfacePropertyCompatibility<const char *>(this,
+ p,
+ config,
+ "empty",
+ NumberMaxType, 0);
+}
+
+//----------------------------------------------------------------------------
+cmComputeLinkInformation*
+cmGeneratorTarget::GetLinkInformation(const std::string& config) const
+{
+ // Lookup any existing information for this configuration.
+ std::string key(cmSystemTools::UpperCase(config));
+ cmTargetLinkInformationMap::iterator
+ i = this->LinkInformation.find(key);
+ if(i == this->LinkInformation.end())
+ {
+ // Compute information for this configuration.
+ cmComputeLinkInformation* info =
+ new cmComputeLinkInformation(this, config);
+ if(!info || !info->Compute())
+ {
+ delete info;
+ info = 0;
+ }
+
+ // Store the information for this configuration.
+ cmTargetLinkInformationMap::value_type entry(key, info);
+ i = this->LinkInformation.insert(entry).first;
+
+ if (info)
+ {
+ this->CheckPropertyCompatibility(info, config);
+ }
+ }
+ return i->second;
+}
+
+//----------------------------------------------------------------------------
+void
+cmGeneratorTarget::ReportPropertyOrigin(const std::string &p,
+ const std::string &result,
+ const std::string &report,
+ const std::string &compatibilityType) const
+{
+ std::vector<std::string> debugProperties;
+ const char *debugProp = this->Target->GetMakefile()
+ ->GetDefinition("CMAKE_DEBUG_TARGET_PROPERTIES");
+ if (debugProp)
+ {
+ cmSystemTools::ExpandListArgument(debugProp, debugProperties);
+ }
+
+ bool debugOrigin = !this->DebugCompatiblePropertiesDone[p]
+ && std::find(debugProperties.begin(),
+ debugProperties.end(),
+ p)
+ != debugProperties.end();
+
+ if (this->Target->GetMakefile()->IsConfigured())
+ {
+ this->DebugCompatiblePropertiesDone[p] = true;
+ }
+ if (!debugOrigin)
+ {
+ return;
+ }
+
+ std::string areport = compatibilityType;
+ areport += std::string(" of property \"") + p + "\" for target \"";
+ areport += std::string(this->GetName());
+ areport += "\" (result: \"";
+ areport += result;
+ areport += "\"):\n" + report;
+
+ this->Makefile->GetCMakeInstance()->IssueMessage(cmake::LOG, areport);
+}
diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h
index a584c71..68e7a8a 100644
--- a/Source/cmGeneratorTarget.h
+++ b/Source/cmGeneratorTarget.h
@@ -20,11 +20,13 @@ class cmLocalGenerator;
class cmMakefile;
class cmSourceFile;
class cmTarget;
+class cmComputeLinkInformation;
class cmGeneratorTarget
{
public:
cmGeneratorTarget(cmTarget*, cmLocalGenerator* lg);
+ ~cmGeneratorTarget();
cmLocalGenerator* GetLocalGenerator() const;
@@ -36,6 +38,9 @@ public:
location is suitable for use as the LOCATION target property. */
const char* GetLocationForBuild() const;
+ cmComputeLinkInformation*
+ GetLinkInformation(const std::string& config) const;
+
int GetType() const;
std::string GetName() const;
const char *GetProperty(const std::string& prop) const;
@@ -82,6 +87,26 @@ public:
bool GetFeatureAsBool(const std::string& feature,
const std::string& config) const;
+ bool IsLinkInterfaceDependentBoolProperty(const std::string &p,
+ const std::string& config) const;
+ bool IsLinkInterfaceDependentStringProperty(const std::string &p,
+ const std::string& config) const;
+ bool IsLinkInterfaceDependentNumberMinProperty(const std::string &p,
+ const std::string& config) const;
+ bool IsLinkInterfaceDependentNumberMaxProperty(const std::string &p,
+ const std::string& config) const;
+
+ bool GetLinkInterfaceDependentBoolProperty(const std::string &p,
+ const std::string& config) const;
+
+ const char *GetLinkInterfaceDependentStringProperty(const std::string &p,
+ const std::string& config) const;
+ const char *GetLinkInterfaceDependentNumberMinProperty(const std::string &p,
+ const std::string& config) const;
+ const char *GetLinkInterfaceDependentNumberMaxProperty(const std::string &p,
+ const std::string& config) const;
+
+
/** Get the full path to the target according to the settings in its
makefile and the configuration type. */
std::string GetFullPath(const std::string& config="", bool implib = false,
@@ -90,6 +115,53 @@ public:
bool realname) const;
std::string NormalGetRealName(const std::string& config) const;
+ /** @return the Mac App directory without the base */
+ std::string GetAppBundleDirectory(const std::string& config,
+ bool contentOnly) const;
+
+ /** Return whether this target is an executable Bundle, a framework
+ or CFBundle on Apple. */
+ bool IsBundleOnApple() const;
+
+ /** Get the full name of the target according to the settings in its
+ makefile. */
+ std::string GetFullName(const std::string& config="",
+ bool implib = false) const;
+
+ /** @return the Mac framework directory without the base. */
+ std::string GetFrameworkDirectory(const std::string& config,
+ bool rootDir) const;
+
+ /** @return the Mac CFBundle directory without the base */
+ std::string GetCFBundleDirectory(const std::string& config,
+ bool contentOnly) const;
+
+ /** Return the install name directory for the target in the
+ * build tree. For example: "\@rpath/", "\@loader_path/",
+ * or "/full/path/to/library". */
+ std::string GetInstallNameDirForBuildTree(const std::string& config) const;
+
+ /** Return the install name directory for the target in the
+ * install tree. For example: "\@rpath/" or "\@loader_path/". */
+ std::string GetInstallNameDirForInstallTree() const;
+
+ /** Get the soname of the target. Allowed only for a shared library. */
+ std::string GetSOName(const std::string& config) const;
+
+ void GetFullNameComponents(std::string& prefix,
+ std::string& base, std::string& suffix,
+ const std::string& config="",
+ bool implib = false) const;
+
+ /** Append to @a base the mac content directory and return it. */
+ std::string BuildMacContentDirectory(const std::string& base,
+ const std::string& config = "",
+ bool contentOnly = true) const;
+
+ /** @return the mac content directory for this target. */
+ std::string GetMacContentDirectory(const std::string& config = 0,
+ bool implib = false) const;
+
cmTarget* Target;
cmMakefile* Makefile;
cmLocalGenerator* LocalGenerator;
@@ -97,6 +169,20 @@ public:
std::string GetModuleDefinitionFile(const std::string& config) const;
+ /** Link information from the transitive closure of the link
+ implementation and the interfaces of its dependencies. */
+ struct LinkClosure
+ {
+ // The preferred linker language.
+ std::string LinkerLanguage;
+
+ // Languages whose runtime libraries must be linked.
+ std::vector<std::string> Languages;
+ };
+
+ LinkClosure const* GetLinkClosure(const std::string& config) const;
+ void ComputeLinkClosure(const std::string& config, LinkClosure& lc) const;
+
/** Full path with trailing slash to the top-level directory
holding object files for this target. Includes the build
time config name placeholder if needed for the generator. */
@@ -128,10 +214,41 @@ public:
*/
void TraceDependencies();
+ /** Get the directory in which to place the target compiler .pdb file.
+ If the configuration name is given then the generator will add its
+ subdirectory for that configuration. Otherwise just the canonical
+ compiler pdb output directory is given. */
+ std::string GetCompilePDBDirectory(const std::string& config = "") const;
+
/** Get sources that must be built before the given source. */
std::vector<cmSourceFile*> const*
GetSourceDepends(cmSourceFile const* sf) const;
+ /** Get the name of the pdb file for the target. */
+ std::string GetPDBName(const std::string& config="") const;
+
+ /** Whether this library has soname enabled and platform supports it. */
+ bool HasSOName(const std::string& config) const;
+
+ struct CompileInfo
+ {
+ std::string CompilePdbDir;
+ };
+
+ CompileInfo const* GetCompileInfo(const std::string& config) const;
+
+ typedef std::map<std::string, CompileInfo> CompileInfoMapType;
+ mutable CompileInfoMapType CompileInfoMap;
+
+ /** Get the name of the compiler pdb file for the target. */
+ std::string GetCompilePDBName(const std::string& config="") const;
+
+ /** Get the path for the MSVC /Fd option for this target. */
+ std::string GetCompilePDBPath(const std::string& config="") const;
+
+ // Get the target base name.
+ std::string GetOutputName(const std::string& config, bool implib) const;
+
/**
* Flags for a given source file as used in this target. Typically assigned
* via SET_TARGET_PROPERTIES when the property is a list of source files.
@@ -153,6 +270,33 @@ public:
SourceFileType Type;
const char* MacFolder; // location inside Mac content folders
};
+ void GetAutoUicOptions(std::vector<std::string> &result,
+ const std::string& config) const;
+
+ /** Get the names of the executable needed to generate a build rule
+ that takes into account executable version numbers. This should
+ be called only on an executable target. */
+ void GetExecutableNames(std::string& name, std::string& realName,
+ std::string& impName, std::string& pdbName,
+ const std::string& config) const;
+
+ /** Get the names of the library needed to generate a build rule
+ that takes into account shared library version numbers. This
+ should be called only on a library target. */
+ void GetLibraryNames(std::string& name, std::string& soName,
+ std::string& realName, std::string& impName,
+ std::string& pdbName, const std::string& config) const;
+
+ /**
+ * Compute whether this target must be relinked before installing.
+ */
+ bool NeedRelinkBeforeInstall(const std::string& config) const;
+
+ /** Return true if builtin chrpath will work for this target */
+ bool IsChrpathUsed(const std::string& config) const;
+
+ ///! Return the preferred linker language for this target
+ std::string GetLinkerLanguage(const std::string& config = "") const;
struct SourceFileFlags
GetTargetSourceFileFlags(const cmSourceFile* sf) const;
@@ -168,12 +312,16 @@ public:
std::vector<cmSourceFile const*> XamlSources;
};
+ void ReportPropertyOrigin(const std::string &p,
+ const std::string &result,
+ const std::string &report,
+ const std::string &compatibilityType) const;
+
private:
friend class cmTargetTraceDependencies;
struct SourceEntry { std::vector<cmSourceFile*> Depends; };
typedef std::map<cmSourceFile const*, SourceEntry> SourceEntriesType;
SourceEntriesType SourceEntries;
-
mutable std::map<cmSourceFile const*, std::string> Objects;
std::set<cmSourceFile const*> ExplicitObjectName;
mutable std::map<std::string, std::vector<std::string> > SystemIncludesCache;
@@ -182,8 +330,55 @@ private:
mutable bool SourceFileFlagsConstructed;
mutable std::map<cmSourceFile const*, SourceFileFlags> SourceFlagsMap;
+ mutable std::map<std::string, bool> DebugCompatiblePropertiesDone;
+
+ std::string GetFullNameInternal(const std::string& config,
+ bool implib) const;
+ void GetFullNameInternal(const std::string& config, bool implib,
+ std::string& outPrefix, std::string& outBase,
+ std::string& outSuffix) const;
+
+ typedef std::map<std::string, LinkClosure> LinkClosureMapType;
+ mutable LinkClosureMapType LinkClosureMap;
+
+ struct CompatibleInterfacesBase
+ {
+ std::set<std::string> PropsBool;
+ std::set<std::string> PropsString;
+ std::set<std::string> PropsNumberMax;
+ std::set<std::string> PropsNumberMin;
+ };
+ CompatibleInterfacesBase const&
+ GetCompatibleInterfaces(std::string const& config) const;
+
+ struct CompatibleInterfaces: public CompatibleInterfacesBase
+ {
+ CompatibleInterfaces(): Done(false) {}
+ bool Done;
+ };
+ mutable std::map<std::string, CompatibleInterfaces> CompatibleInterfacesMap;
+
+ typedef std::map<std::string, cmComputeLinkInformation*>
+ cmTargetLinkInformationMap;
+ mutable cmTargetLinkInformationMap LinkInformation;
+
+ void CheckPropertyCompatibility(cmComputeLinkInformation *info,
+ const std::string& config) const;
+
cmGeneratorTarget(cmGeneratorTarget const&);
void operator=(cmGeneratorTarget const&);
+
+ struct LinkImplClosure: public std::vector<cmTarget const*>
+ {
+ LinkImplClosure(): Done(false) {}
+ bool Done;
+ };
+ mutable std::map<std::string, LinkImplClosure> LinkImplClosureMap;
+
+public:
+ std::vector<cmTarget const*> const&
+ GetLinkImplementationClosure(const std::string& config) const;
+
};
struct cmStrictTargetComparison {
diff --git a/Source/cmGetDirectoryPropertyCommand.cxx b/Source/cmGetDirectoryPropertyCommand.cxx
index c056d95..2558876 100644
--- a/Source/cmGetDirectoryPropertyCommand.cxx
+++ b/Source/cmGetDirectoryPropertyCommand.cxx
@@ -51,10 +51,8 @@ bool cmGetDirectoryPropertyCommand
sd = cmSystemTools::CollapseFullPath(sd);
// lookup the makefile from the directory name
- cmLocalGenerator *lg =
- this->Makefile->GetGlobalGenerator()->
- FindLocalGenerator(sd);
- if (!lg)
+ dir = this->Makefile->GetGlobalGenerator()->FindMakefile(sd);
+ if (!dir)
{
this->SetError
("DIRECTORY argument provided but requested directory not found. "
@@ -62,7 +60,6 @@ bool cmGetDirectoryPropertyCommand
"it is valid but has not been processed yet.");
return false;
}
- dir = lg->GetMakefile();
++i;
}
diff --git a/Source/cmGetFilenameComponentCommand.cxx b/Source/cmGetFilenameComponentCommand.cxx
index 67f9f2d..13a9afb 100644
--- a/Source/cmGetFilenameComponentCommand.cxx
+++ b/Source/cmGetFilenameComponentCommand.cxx
@@ -24,7 +24,7 @@ bool cmGetFilenameComponentCommand
// Check and see if the value has been stored in the cache
// already, if so use that value
- if(args.size() == 4 && args[3] == "CACHE")
+ if(args.size() >= 4 && args[args.size() - 1] == "CACHE")
{
const char* cacheValue = this->Makefile->GetDefinition(args[0]);
if(cacheValue && !cmSystemTools::IsNOTFOUND(cacheValue))
@@ -111,7 +111,7 @@ bool cmGetFilenameComponentCommand
return false;
}
- if(args.size() == 4 && args[3] == "CACHE")
+ if(args.size() >= 4 && args[args.size() - 1] == "CACHE")
{
if(!programArgs.empty() && !storeArgs.empty())
{
diff --git a/Source/cmGetPropertyCommand.cxx b/Source/cmGetPropertyCommand.cxx
index 33d638b..4c42f53 100644
--- a/Source/cmGetPropertyCommand.cxx
+++ b/Source/cmGetPropertyCommand.cxx
@@ -262,13 +262,8 @@ bool cmGetPropertyCommand::HandleDirectoryMode()
dir = cmSystemTools::CollapseFullPath(dir);
// Lookup the generator.
- if(cmLocalGenerator* lg =
- (this->Makefile->GetGlobalGenerator()->FindLocalGenerator(dir)))
- {
- // Use the makefile for the directory found.
- mf = lg->GetMakefile();
- }
- else
+ mf = this->Makefile->GetGlobalGenerator()->FindMakefile(dir);
+ if (!mf)
{
// Could not find the directory.
this->SetError
diff --git a/Source/cmGhsMultiTargetGenerator.cxx b/Source/cmGhsMultiTargetGenerator.cxx
index 2f9265a..1e57c33 100644
--- a/Source/cmGhsMultiTargetGenerator.cxx
+++ b/Source/cmGhsMultiTargetGenerator.cxx
@@ -128,7 +128,8 @@ void cmGhsMultiTargetGenerator::Generate()
{
config = "RELEASE";
}
- const std::string language(this->Target->GetLinkerLanguage(config));
+ const std::string language(
+ this->GeneratorTarget->GetLinkerLanguage(config));
config = cmSystemTools::UpperCase(config);
this->DynamicDownload = this->DetermineIfDynamicDownload(config, language);
if (this->DynamicDownload)
diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx
index 5599854..cda26cd 100644
--- a/Source/cmGlobalGenerator.cxx
+++ b/Source/cmGlobalGenerator.cxx
@@ -14,6 +14,20 @@
#if defined(_MSC_VER) && _MSC_VER >= 1800
# define KWSYS_WINDOWS_DEPRECATED_GetVersionEx
#endif
+typedef struct {
+ ULONG dwOSVersionInfoSize;
+ ULONG dwMajorVersion;
+ ULONG dwMinorVersion;
+ ULONG dwBuildNumber;
+ ULONG dwPlatformId;
+ WCHAR szCSDVersion[128];
+ USHORT wServicePackMajor;
+ USHORT wServicePackMinor;
+ USHORT wSuiteMask;
+ UCHAR wProductType;
+ UCHAR wReserved;
+} CMRTL_OSVERSIONINFOEXW;
+
#endif
#include "cmGlobalGenerator.h"
@@ -30,10 +44,10 @@
#include "cmGeneratedFileStream.h"
#include "cmGeneratorTarget.h"
#include "cmGeneratorExpression.h"
-#include "cmGeneratorExpressionEvaluationFile.h"
#include "cmExportBuildFileGenerator.h"
#include "cmCPackPropertiesGenerator.h"
#include "cmAlgorithms.h"
+#include "cmInstallGenerator.h"
#include <cmsys/Directory.hxx>
#include <cmsys/FStream.hxx>
@@ -432,23 +446,45 @@ cmGlobalGenerator::EnableLanguage(std::vector<std::string>const& languages,
if (!mf->GetDefinition("CMAKE_SYSTEM"))
{
#if defined(_WIN32) && !defined(__CYGWIN__)
- /* Windows version number data. */
- OSVERSIONINFO osvi;
- ZeroMemory(&osvi, sizeof(osvi));
- osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ CMRTL_OSVERSIONINFOEXW osviex;
+ ZeroMemory(&osviex, sizeof(osviex));
+ osviex.dwOSVersionInfoSize = sizeof(osviex);
+
+ typedef LONG (FAR WINAPI *cmRtlGetVersion)(CMRTL_OSVERSIONINFOEXW*);
+ cmRtlGetVersion rtlGetVersion = reinterpret_cast<cmRtlGetVersion>(
+ GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "RtlGetVersion"));
+ if (rtlGetVersion && rtlGetVersion(&osviex) == 0)
+ {
+ std::ostringstream windowsVersionString;
+ windowsVersionString << osviex.dwMajorVersion << "."
+ << osviex.dwMinorVersion << "."
+ << osviex.dwBuildNumber;
+ windowsVersionString.str();
+ mf->AddDefinition("CMAKE_HOST_SYSTEM_VERSION",
+ windowsVersionString.str().c_str());
+ }
+ else
+ {
+ // RtlGetVersion failed, so use the deprecated GetVersionEx function.
+ /* Windows version number data. */
+ OSVERSIONINFO osvi;
+ ZeroMemory(&osvi, sizeof(osvi));
+ osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
#ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
# pragma warning (push)
# pragma warning (disable:4996)
#endif
- GetVersionEx (&osvi);
+ GetVersionEx (&osvi);
#ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
# pragma warning (pop)
#endif
- std::ostringstream windowsVersionString;
- windowsVersionString << osvi.dwMajorVersion << "." << osvi.dwMinorVersion;
- windowsVersionString.str();
- mf->AddDefinition("CMAKE_HOST_SYSTEM_VERSION",
- windowsVersionString.str().c_str());
+ std::ostringstream windowsVersionString;
+ windowsVersionString << osvi.dwMajorVersion << "."
+ << osvi.dwMinorVersion;
+ windowsVersionString.str();
+ mf->AddDefinition("CMAKE_HOST_SYSTEM_VERSION",
+ windowsVersionString.str().c_str());
+ }
#endif
// Read the DetermineSystem file
std::string systemFile = mf->GetModulesFile("CMakeDetermineSystem.cmake");
@@ -1093,6 +1129,7 @@ void cmGlobalGenerator::Configure()
// start with this directory
cmLocalGenerator *lg = this->MakeLocalGenerator();
+ this->Makefiles.push_back(lg->GetMakefile());
this->LocalGenerators.push_back(lg);
// set the Start directories
@@ -1111,9 +1148,9 @@ void cmGlobalGenerator::Configure()
// update the cache entry for the number of local generators, this is used
// for progress
char num[100];
- sprintf(num,"%d",static_cast<int>(this->LocalGenerators.size()));
+ sprintf(num,"%d",static_cast<int>(this->Makefiles.size()));
this->GetCMakeInstance()->AddCacheEntry
- ("CMAKE_NUMBER_OF_LOCAL_GENERATORS", num,
+ ("CMAKE_NUMBER_OF_MAKEFILES", num,
"number of local generators", cmState::INTERNAL);
// check for link libraries and include directories containing "NOTFOUND"
@@ -1156,9 +1193,9 @@ void cmGlobalGenerator::Configure()
cmTargets globalTargets;
this->CreateDefaultGlobalTargets(&globalTargets);
- for (i = 0; i < this->LocalGenerators.size(); ++i)
+ for (i = 0; i < this->Makefiles.size(); ++i)
{
- cmMakefile* mf = this->LocalGenerators[i]->GetMakefile();
+ cmMakefile* mf = this->Makefiles[i];
cmTargets* targets = &(mf->GetTargets());
cmTargets::iterator tit;
for ( tit = globalTargets.begin(); tit != globalTargets.end(); ++ tit )
@@ -1212,7 +1249,7 @@ bool cmGlobalGenerator::CheckALLOW_DUPLICATE_CUSTOM_TARGETS() const
return false;
}
-void cmGlobalGenerator::DoGenerate()
+bool cmGlobalGenerator::Compute()
{
// Some generators track files replaced during the Generate.
// Start with an empty vector:
@@ -1221,17 +1258,11 @@ void cmGlobalGenerator::DoGenerate()
// clear targets to issue warning CMP0042 for
this->CMP0042WarnTargets.clear();
- this->Generate();
-}
-
-void cmGlobalGenerator::Generate()
-{
// Check whether this generator is allowed to run.
if(!this->CheckALLOW_DUPLICATE_CUSTOM_TARGETS())
{
- return;
+ return false;
}
-
this->FinalizeTargetCompileInfo();
this->CreateGenerationObjects();
@@ -1266,6 +1297,24 @@ void cmGlobalGenerator::Generate()
}
#endif
+ for (i = 0; i < this->LocalGenerators.size(); ++i)
+ {
+ cmMakefile* mf = this->LocalGenerators[i]->GetMakefile();
+ std::vector<cmInstallGenerator*>& gens = mf->GetInstallGenerators();
+ for (std::vector<cmInstallGenerator*>::const_iterator git = gens.begin();
+ git != gens.end(); ++git)
+ {
+ (*git)->Compute(this->LocalGenerators[i]);
+ }
+ }
+
+ return true;
+}
+
+void cmGlobalGenerator::Generate()
+{
+ unsigned int i;
+
// Trace the dependencies, after that no custom commands should be added
// because their dependencies might not be handled correctly
for (i = 0; i < this->LocalGenerators.size(); ++i)
@@ -1433,9 +1482,9 @@ void cmGlobalGenerator::CreateQtAutoGeneratorsTargets(AutogensType &autogens)
void cmGlobalGenerator::FinalizeTargetCompileInfo()
{
// Construct per-target generator information.
- for(unsigned int i=0; i < this->LocalGenerators.size(); ++i)
+ for(unsigned int i=0; i < this->Makefiles.size(); ++i)
{
- cmMakefile *mf = this->LocalGenerators[i]->GetMakefile();
+ cmMakefile *mf = this->Makefiles[i];
const cmStringRange noconfig_compile_definitions =
mf->GetCompileDefinitionsEntries();
@@ -1501,6 +1550,7 @@ void cmGlobalGenerator::CreateGeneratorTargets(TargetTypes targetTypes,
ti != targets.end(); ++ti)
{
cmTarget* t = &ti->second;
+ t->Compute();
cmGeneratorTarget* gt = new cmGeneratorTarget(t, lg);
this->GeneratorTargets[t] = gt;
generatorTargets[t] = gt;
@@ -1548,12 +1598,11 @@ void cmGlobalGenerator::ClearGeneratorMembers()
cmDeleteAll(this->GeneratorTargets);
this->GeneratorTargets.clear();
- cmDeleteAll(this->EvaluationFiles);
- this->EvaluationFiles.clear();
-
cmDeleteAll(this->BuildExportSets);
this->BuildExportSets.clear();
+ this->Makefiles.clear();
+
cmDeleteAll(this->LocalGenerators);
this->LocalGenerators.clear();
@@ -1593,11 +1642,11 @@ void cmGlobalGenerator::CheckLocalGenerators()
// std::set<std::string> notFoundMap;
// after it is all done do a ConfigureFinalPass
cmState* state = this->GetCMakeInstance()->GetState();
- for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i)
+ for (unsigned int i = 0; i < this->Makefiles.size(); ++i)
{
- this->LocalGenerators[i]->GetMakefile()->ConfigureFinalPass();
+ this->Makefiles[i]->ConfigureFinalPass();
cmTargets &targets =
- this->LocalGenerators[i]->GetMakefile()->GetTargets();
+ this->Makefiles[i]->GetTargets();
for (cmTargets::iterator l = targets.begin();
l != targets.end(); l++)
{
@@ -1652,15 +1701,14 @@ void cmGlobalGenerator::CheckLocalGenerators()
}
std::string text = notFoundMap[varName];
text += "\n used as include directory in directory ";
- text += this->LocalGenerators[i]
- ->GetMakefile()->GetCurrentSourceDirectory();
+ text += this->Makefiles[i]->GetCurrentSourceDirectory();
notFoundMap[varName] = text;
}
}
}
this->CMakeInstance->UpdateProgress
("Configuring", 0.9f+0.1f*(static_cast<float>(i)+1.0f)/
- static_cast<float>(this->LocalGenerators.size()));
+ static_cast<float>(this->Makefiles.size()));
}
if(!notFoundMap.empty())
@@ -1694,9 +1742,9 @@ int cmGlobalGenerator::TryCompile(const std::string& srcdir,
// take the bulk of the time, so try and guess some progress
// by getting closer and closer to 100 without actually getting there.
if (!this->CMakeInstance->GetState()->GetInitializedCacheValue
- ("CMAKE_NUMBER_OF_LOCAL_GENERATORS"))
+ ("CMAKE_NUMBER_OF_MAKEFILES"))
{
- // If CMAKE_NUMBER_OF_LOCAL_GENERATORS is not set
+ // If CMAKE_NUMBER_OF_MAKEFILES is not set
// we are in the first time progress and we have no
// idea how long it will be. So, just move 1/10th of the way
// there each time, and don't go over 95%
@@ -1884,19 +1932,19 @@ std::string cmGlobalGenerator::GenerateCMakeBuildCommand(
}
//----------------------------------------------------------------------------
-void cmGlobalGenerator::AddLocalGenerator(cmLocalGenerator *lg)
+void cmGlobalGenerator::AddMakefile(cmMakefile *mf)
{
- this->LocalGenerators.push_back(lg);
+ this->Makefiles.push_back(mf);
// update progress
// estimate how many lg there will be
const char *numGenC =
this->CMakeInstance->GetState()->GetInitializedCacheValue
- ("CMAKE_NUMBER_OF_LOCAL_GENERATORS");
+ ("CMAKE_NUMBER_OF_MAKEFILES");
if (!numGenC)
{
- // If CMAKE_NUMBER_OF_LOCAL_GENERATORS is not set
+ // If CMAKE_NUMBER_OF_MAKEFILES is not set
// we are in the first time progress and we have no
// idea how long it will be. So, just move half way
// there each time, and don't go over 95%
@@ -1911,7 +1959,7 @@ void cmGlobalGenerator::AddLocalGenerator(cmLocalGenerator *lg)
}
int numGen = atoi(numGenC);
- float prog = 0.9f*static_cast<float>(this->LocalGenerators.size())/
+ float prog = 0.9f*static_cast<float>(this->Makefiles.size())/
static_cast<float>(numGen);
if (prog > 0.9f)
{
@@ -1920,6 +1968,12 @@ void cmGlobalGenerator::AddLocalGenerator(cmLocalGenerator *lg)
this->CMakeInstance->UpdateProgress("Configuring", prog);
}
+//----------------------------------------------------------------------------
+void cmGlobalGenerator::AddLocalGenerator(cmLocalGenerator *lg)
+{
+ this->LocalGenerators.push_back(lg);
+}
+
void cmGlobalGenerator::AddInstallComponent(const char* component)
{
if(component && *component)
@@ -2009,10 +2063,10 @@ bool cmGlobalGenerator::IsExcluded(cmLocalGenerator* root,
}
bool cmGlobalGenerator::IsExcluded(cmLocalGenerator* root,
- cmTarget const& target) const
+ cmGeneratorTarget* target) const
{
- if(target.GetType() == cmTarget::INTERFACE_LIBRARY
- || target.GetPropertyAsBool("EXCLUDE_FROM_ALL"))
+ if(target->GetType() == cmTarget::INTERFACE_LIBRARY
+ || target->Target->GetPropertyAsBool("EXCLUDE_FROM_ALL"))
{
// This target is excluded from its directory.
return true;
@@ -2021,7 +2075,7 @@ bool cmGlobalGenerator::IsExcluded(cmLocalGenerator* root,
{
// This target is included in its directory. Check whether the
// directory is excluded.
- return this->IsExcluded(root, target.GetMakefile()->GetLocalGenerator());
+ return this->IsExcluded(root, target->GetLocalGenerator());
}
}
@@ -2082,15 +2136,16 @@ void cmGlobalGenerator::FillLocalGeneratorToTargetMap()
{
cmTarget const& target = t->second;
+ cmGeneratorTarget* gt = this->GetGeneratorTarget(&target);
+
// Consider the directory containing the target and all its
// parents until something excludes the target.
- for(cmLocalGenerator* clg = lg; clg && !this->IsExcluded(clg, target);
+ for(cmLocalGenerator* clg = lg; clg && !this->IsExcluded(clg, gt);
clg = clg->GetParent())
{
// This local generator includes the target.
std::set<cmGeneratorTarget const*>& targetSet =
this->LocalGeneratorToTargetMap[clg];
- cmGeneratorTarget* gt = this->GetGeneratorTarget(&target);
targetSet.insert(gt);
// Add dependencies of the included target. An excluded
@@ -2107,6 +2162,20 @@ void cmGlobalGenerator::FillLocalGeneratorToTargetMap()
}
}
+cmMakefile*
+cmGlobalGenerator::FindMakefile(const std::string& start_dir) const
+{
+ for(std::vector<cmMakefile*>::const_iterator it =
+ this->Makefiles.begin(); it != this->Makefiles.end(); ++it)
+ {
+ std::string sd = (*it)->GetCurrentSourceDirectory();
+ if (sd == start_dir)
+ {
+ return *it;
+ }
+ }
+ return 0;
+}
///! Find a local generator by its startdirectory
cmLocalGenerator*
@@ -2194,7 +2263,7 @@ inline std::string removeQuotes(const std::string& s)
void cmGlobalGenerator::CreateDefaultGlobalTargets(cmTargets* targets)
{
- cmMakefile* mf = this->LocalGenerators[0]->GetMakefile();
+ cmMakefile* mf = this->Makefiles[0];
const char* cmakeCfgIntDir = this->GetCMakeCFGIntDir();
// CPack
@@ -2698,12 +2767,8 @@ void cmGlobalGenerator::AddTargetDepends(cmGeneratorTarget const* target,
//----------------------------------------------------------------------------
-void cmGlobalGenerator::AddToManifest(const std::string& config,
- std::string const& f)
+void cmGlobalGenerator::AddToManifest(std::string const& f)
{
- // Add to the main manifest for this configuration.
- this->TargetManifest[config].insert(f);
-
// Add to the content listing for the file's directory.
std::string dir = cmSystemTools::GetFilenamePath(f);
std::string file = cmSystemTools::GetFilenameName(f);
@@ -2771,9 +2836,9 @@ cmGlobalGenerator::AddRuleHash(const std::vector<std::string>& outputs,
}
// Shorten the output name (in expected use case).
- cmLocalGenerator* lg = this->GetLocalGenerators()[0];
- std::string fname = lg->Convert(outputs[0],
- cmLocalGenerator::HOME_OUTPUT);
+ cmOutputConverter converter(this->GetMakefiles()[0]->GetStateSnapshot());
+ std::string fname = converter.Convert(
+ outputs[0], cmLocalGenerator::HOME_OUTPUT);
// Associate the hash with this output.
this->RuleHashes[fname] = hash;
@@ -3023,61 +3088,21 @@ cmGlobalGenerator::GetFilenameTargetDepends(cmSourceFile* sf) const {
void cmGlobalGenerator::CreateEvaluationSourceFiles(
std::string const& config) const
{
- for(std::vector<cmGeneratorExpressionEvaluationFile*>::const_iterator
- li = this->EvaluationFiles.begin();
- li != this->EvaluationFiles.end();
- ++li)
+ unsigned int i;
+ for (i = 0; i < this->LocalGenerators.size(); ++i)
{
- (*li)->CreateOutputFile(config);
+ this->LocalGenerators[i]->CreateEvaluationFileOutputs(config);
}
}
//----------------------------------------------------------------------------
-void cmGlobalGenerator::AddEvaluationFile(const std::string &inputFile,
- cmsys::auto_ptr<cmCompiledGeneratorExpression> outputExpr,
- cmMakefile *makefile,
- cmsys::auto_ptr<cmCompiledGeneratorExpression> condition,
- bool inputIsContent)
-{
- this->EvaluationFiles.push_back(
- new cmGeneratorExpressionEvaluationFile(inputFile, outputExpr,
- makefile, condition,
- inputIsContent));
-}
-
-//----------------------------------------------------------------------------
void cmGlobalGenerator::ProcessEvaluationFiles()
{
std::vector<std::string> generatedFiles;
- for(std::vector<cmGeneratorExpressionEvaluationFile*>::const_iterator
- li = this->EvaluationFiles.begin();
- li != this->EvaluationFiles.end();
- ++li)
+ unsigned int i;
+ for (i = 0; i < this->LocalGenerators.size(); ++i)
{
- (*li)->Generate();
- if (cmSystemTools::GetFatalErrorOccured())
- {
- return;
- }
- std::vector<std::string> files = (*li)->GetFiles();
- std::sort(files.begin(), files.end());
-
- std::vector<std::string> intersection;
- std::set_intersection(files.begin(), files.end(),
- generatedFiles.begin(), generatedFiles.end(),
- std::back_inserter(intersection));
- if (!intersection.empty())
- {
- cmSystemTools::Error("Files to be generated by multiple different "
- "commands: ", cmWrap('"', intersection, '"', " ").c_str());
- return;
- }
-
- generatedFiles.insert(generatedFiles.end(),
- files.begin(), files.end());
- std::vector<std::string>::iterator newIt =
- generatedFiles.end() - files.size();
- std::inplace_merge(generatedFiles.begin(), newIt, generatedFiles.end());
+ this->LocalGenerators[i]->ProcessEvaluationFiles(generatedFiles);
}
}
diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h
index d486003..a13bede 100644
--- a/Source/cmGlobalGenerator.h
+++ b/Source/cmGlobalGenerator.h
@@ -34,7 +34,6 @@
class cmake;
class cmGeneratorTarget;
-class cmGeneratorExpressionEvaluationFile;
class cmMakefile;
class cmLocalGenerator;
class cmExternalMakefileProjectGenerator;
@@ -86,6 +85,7 @@ public:
*/
virtual void Configure();
+ virtual bool Compute();
enum TargetTypes {
AllTargets,
@@ -99,7 +99,7 @@ public:
* basically creates a series of LocalGenerators for each directory and
* requests that they Generate.
*/
- void DoGenerate();
+ virtual void Generate();
/**
* Set/Get and Clear the enabled languages.
@@ -173,6 +173,8 @@ public:
cmake *GetCMakeInstance() const { return this->CMakeInstance; }
void SetConfiguredFilesPath(cmGlobalGenerator* gen);
+ const std::vector<cmMakefile*>& GetMakefiles() const {
+ return this->Makefiles;}
const std::vector<cmLocalGenerator *>& GetLocalGenerators() const {
return this->LocalGenerators;}
@@ -184,6 +186,7 @@ public:
void SetCurrentMakefile(cmMakefile* mf)
{this->CurrentMakefile = mf;}
+ void AddMakefile(cmMakefile *mf);
void AddLocalGenerator(cmLocalGenerator *lg);
///! Set an generator for an "external makefile based project"
@@ -200,7 +203,7 @@ public:
cmExportSetMap& GetExportSets() {return this->ExportSets;}
/** Add a file to the manifest of generated targets for a configuration. */
- void AddToManifest(const std::string& config, std::string const& f);
+ void AddToManifest(std::string const& f);
void EnableInstallTarget();
@@ -253,6 +256,7 @@ public:
that is a framework. */
bool NameResolvesToFramework(const std::string& libname) const;
+ cmMakefile* FindMakefile(const std::string& start_dir) const;
///! Find a local generator by its startdirectory
cmLocalGenerator* FindLocalGenerator(const std::string& start_dir) const;
@@ -264,11 +268,6 @@ public:
const std::string& suffix,
std::string& dir);
- /** Get the manifest of all targets that will be built for each
- configuration. This is valid during generation only. */
- cmTargetManifest const& GetTargetManifest() const
- { return this->TargetManifest; }
-
/** Get the content of a directory. Directory listings are cached
and re-loaded from disk only when modified. During the generation
step the content will include the target files to be built even if
@@ -338,12 +337,6 @@ public:
static std::string EscapeJSON(const std::string& s);
- void AddEvaluationFile(const std::string &inputFile,
- cmsys::auto_ptr<cmCompiledGeneratorExpression> outputName,
- cmMakefile *makefile,
- cmsys::auto_ptr<cmCompiledGeneratorExpression> condition,
- bool inputIsContent);
-
void ProcessEvaluationFiles();
std::map<std::string, cmExportBuildFileGenerator*>& GetBuildExportSets()
@@ -373,8 +366,6 @@ public:
std::string MakeSilentFlag;
protected:
- virtual void Generate();
-
typedef std::vector<cmLocalGenerator*> GeneratorVector;
// for a project collect all its targets by following depend
// information, and also collect all the targets
@@ -387,6 +378,8 @@ protected:
void SetLanguageEnabledFlag(const std::string& l, cmMakefile* mf);
void SetLanguageEnabledMaps(const std::string& l, cmMakefile* mf);
void FillExtensionToLanguageMap(const std::string& l, cmMakefile* mf);
+ virtual void PrintCompilerAdvice(std::ostream& os, std::string const& lang,
+ const char* envVar) const;
virtual bool ComputeTargetDepends();
@@ -404,7 +397,7 @@ protected:
void FillProjectMap();
void CheckLocalGenerators();
bool IsExcluded(cmLocalGenerator* root, cmLocalGenerator* gen) const;
- bool IsExcluded(cmLocalGenerator* root, cmTarget const& target) const;
+ bool IsExcluded(cmLocalGenerator* root, cmGeneratorTarget* target) const;
void FillLocalGeneratorToTargetMap();
void CreateDefaultGlobalTargets(cmTargets* targets);
cmTarget CreateGlobalTarget(const std::string& name, const char* message,
@@ -415,6 +408,7 @@ protected:
std::string FindMakeProgramFile;
std::string ConfiguredFilesPath;
cmake *CMakeInstance;
+ std::vector<cmMakefile*> Makefiles;
std::vector<cmLocalGenerator *> LocalGenerators;
cmMakefile* CurrentMakefile;
// map from project name to vector of local generators in that project
@@ -429,10 +423,6 @@ protected:
std::map<std::string, cmExportBuildFileGenerator*> BuildExportSets;
std::map<std::string, cmExportBuildFileGenerator*> BuildExportExportSets;
- // Manifest of all targets that will be built for each configuration.
- // This is computed just before local generators generate.
- cmTargetManifest TargetManifest;
-
// All targets in the entire project.
#if defined(CMAKE_BUILD_WITH_CMAKE)
#ifdef CMake_HAVE_CXX11_UNORDERED_MAP
@@ -446,7 +436,6 @@ protected:
TargetMap TotalTargets;
TargetMap AliasTargets;
TargetMap ImportedTargets;
- std::vector<cmGeneratorExpressionEvaluationFile*> EvaluationFiles;
const char* GetPredefinedTargetsFolder();
virtual bool UseFolderProperty();
@@ -480,8 +469,6 @@ private:
virtual void ForceLinkerLanguages();
- virtual void PrintCompilerAdvice(std::ostream& os, std::string const& lang,
- const char* envVar) const;
void CheckCompilerIdCompatibility(cmMakefile* mf,
std::string const& lang) const;
diff --git a/Source/cmGlobalJOMMakefileGenerator.cxx b/Source/cmGlobalJOMMakefileGenerator.cxx
index 50e7053..3f33f91 100644
--- a/Source/cmGlobalJOMMakefileGenerator.cxx
+++ b/Source/cmGlobalJOMMakefileGenerator.cxx
@@ -36,18 +36,6 @@ void cmGlobalJOMMakefileGenerator
// pick a default
mf->AddDefinition("CMAKE_GENERATOR_CC", "cl");
mf->AddDefinition("CMAKE_GENERATOR_CXX", "cl");
- if(!(cmSystemTools::GetEnv("INCLUDE") &&
- cmSystemTools::GetEnv("LIB"))
- )
- {
- std::string message = "To use the JOM generator, cmake must be run "
- "from a shell that can use the compiler cl from the command line. "
- "This environment does not contain INCLUDE, LIB, or LIBPATH, and "
- "these must be set for the cl compiler to work. ";
- mf->IssueMessage(cmake::WARNING,
- message);
- }
-
this->cmGlobalUnixMakefileGenerator3::EnableLanguage(l, mf, optional);
}
@@ -58,3 +46,19 @@ void cmGlobalJOMMakefileGenerator
entry.Name = cmGlobalJOMMakefileGenerator::GetActualName();
entry.Brief = "Generates JOM makefiles.";
}
+
+//----------------------------------------------------------------------------
+void cmGlobalJOMMakefileGenerator::PrintCompilerAdvice(std::ostream& os,
+ std::string const& lang,
+ const char* envVar) const
+{
+ if(lang == "CXX" || lang == "C")
+ {
+ os <<
+ "To use the JOM generator with Visual C++, cmake must be run from a "
+ "shell that can use the compiler cl from the command line. This "
+ "environment is unable to invoke the cl compiler. To fix this problem, "
+ "run cmake from the Visual Studio Command Prompt (vcvarsall.bat).\n";
+ }
+ this->cmGlobalUnixMakefileGenerator3::PrintCompilerAdvice(os, lang, envVar);
+}
diff --git a/Source/cmGlobalJOMMakefileGenerator.h b/Source/cmGlobalJOMMakefileGenerator.h
index 2185b23..1869fed 100644
--- a/Source/cmGlobalJOMMakefileGenerator.h
+++ b/Source/cmGlobalJOMMakefileGenerator.h
@@ -42,6 +42,9 @@ public:
*/
virtual void EnableLanguage(std::vector<std::string>const& languages,
cmMakefile *, bool optional);
+private:
+ void PrintCompilerAdvice(std::ostream& os, std::string const& lang,
+ const char* envVar) const;
};
#endif
diff --git a/Source/cmGlobalNMakeMakefileGenerator.cxx b/Source/cmGlobalNMakeMakefileGenerator.cxx
index 4219c34..7c570a6 100644
--- a/Source/cmGlobalNMakeMakefileGenerator.cxx
+++ b/Source/cmGlobalNMakeMakefileGenerator.cxx
@@ -36,18 +36,6 @@ void cmGlobalNMakeMakefileGenerator
// pick a default
mf->AddDefinition("CMAKE_GENERATOR_CC", "cl");
mf->AddDefinition("CMAKE_GENERATOR_CXX", "cl");
- if(!(cmSystemTools::GetEnv("INCLUDE") &&
- cmSystemTools::GetEnv("LIB"))
- )
- {
- std::string message = "To use the NMake generator, cmake must be run "
- "from a shell that can use the compiler cl from the command line. "
- "This environment does not contain INCLUDE, LIB, or LIBPATH, and "
- "these must be set for the cl compiler to work. ";
- mf->IssueMessage(cmake::WARNING,
- message);
- }
-
this->cmGlobalUnixMakefileGenerator3::EnableLanguage(l, mf, optional);
}
@@ -58,3 +46,19 @@ void cmGlobalNMakeMakefileGenerator
entry.Name = cmGlobalNMakeMakefileGenerator::GetActualName();
entry.Brief = "Generates NMake makefiles.";
}
+
+//----------------------------------------------------------------------------
+void cmGlobalNMakeMakefileGenerator::PrintCompilerAdvice(std::ostream& os,
+ std::string const& lang,
+ const char* envVar) const
+{
+ if(lang == "CXX" || lang == "C")
+ {
+ os <<
+ "To use the NMake generator with Visual C++, cmake must be run from a "
+ "shell that can use the compiler cl from the command line. This "
+ "environment is unable to invoke the cl compiler. To fix this problem, "
+ "run cmake from the Visual Studio Command Prompt (vcvarsall.bat).\n";
+ }
+ this->cmGlobalUnixMakefileGenerator3::PrintCompilerAdvice(os, lang, envVar);
+}
diff --git a/Source/cmGlobalNMakeMakefileGenerator.h b/Source/cmGlobalNMakeMakefileGenerator.h
index dd72c49..3c8375a 100644
--- a/Source/cmGlobalNMakeMakefileGenerator.h
+++ b/Source/cmGlobalNMakeMakefileGenerator.h
@@ -40,6 +40,9 @@ public:
*/
virtual void EnableLanguage(std::vector<std::string>const& languages,
cmMakefile *, bool optional);
+private:
+ void PrintCompilerAdvice(std::ostream& os, std::string const& lang,
+ const char* envVar) const;
};
#endif
diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx
index d24cce8..b92ad32 100644
--- a/Source/cmGlobalNinjaGenerator.cxx
+++ b/Source/cmGlobalNinjaGenerator.cxx
@@ -547,6 +547,18 @@ void cmGlobalNinjaGenerator
// Source/cmake.cxx
void cmGlobalNinjaGenerator::Generate()
{
+ // Check minimum Ninja version.
+ if (cmSystemTools::VersionCompare(cmSystemTools::OP_LESS,
+ CurrentNinjaVersion().c_str(),
+ RequiredNinjaVersion().c_str()))
+ {
+ std::ostringstream msg;
+ msg << "The detected version of Ninja (" << this->CurrentNinjaVersion();
+ msg << ") is less than the version of Ninja required by CMake (";
+ msg << this->RequiredNinjaVersion() << ").";
+ this->GetCMakeInstance()->IssueMessage(cmake::FATAL_ERROR, msg.str());
+ return;
+ }
this->OpenBuildFileStream();
this->OpenRulesFileStream();
@@ -911,9 +923,7 @@ cmGlobalNinjaGenerator
case cmTarget::STATIC_LIBRARY:
case cmTarget::MODULE_LIBRARY:
{
- cmGeneratorTarget *gtgt = target->GetMakefile()->GetLocalGenerator()
- ->GetGlobalGenerator()
- ->GetGeneratorTarget(target);
+ cmGeneratorTarget *gtgt = this->GetGeneratorTarget(target);
outputs.push_back(ng->ConvertToNinjaPath(
gtgt->GetFullPath(configName, false, realname)));
break;
@@ -1055,23 +1065,21 @@ void cmGlobalNinjaGenerator::WriteUnknownExplicitDependencies(std::ostream& os)
{
knownDependencies.insert( ng->ConvertToNinjaPath( *j ) );
}
- }
- knownDependencies.insert( "CMakeCache.txt" );
-
- for(std::vector<cmGeneratorExpressionEvaluationFile*>::const_iterator
- li = this->EvaluationFiles.begin();
- li != this->EvaluationFiles.end();
- ++li)
- {
- //get all the files created by generator expressions and convert them
- //to ninja paths
- std::vector<std::string> files = (*li)->GetFiles();
- typedef std::vector<std::string>::const_iterator vect_it;
- for(vect_it j = files.begin(); j != files.end(); ++j)
+ std::vector<cmGeneratorExpressionEvaluationFile*> const& ef =
+ (*i)->GetMakefile()->GetEvaluationFiles();
+ for(std::vector<cmGeneratorExpressionEvaluationFile*>::const_iterator
+ li = ef.begin(); li != ef.end(); ++li)
{
- knownDependencies.insert( ng->ConvertToNinjaPath( *j ) );
+ //get all the files created by generator expressions and convert them
+ //to ninja paths
+ std::vector<std::string> evaluationFiles = (*li)->GetFiles();
+ for(vect_it j = evaluationFiles.begin(); j != evaluationFiles.end(); ++j)
+ {
+ knownDependencies.insert( ng->ConvertToNinjaPath( *j ) );
+ }
}
}
+ knownDependencies.insert( "CMakeCache.txt" );
for(TargetAliasMap::const_iterator i= this->TargetAliases.begin();
i != this->TargetAliases.end();
@@ -1260,7 +1268,7 @@ std::string cmGlobalNinjaGenerator::ninjaCmd() const
return "ninja";
}
-std::string cmGlobalNinjaGenerator::ninjaVersion() const
+std::string cmGlobalNinjaGenerator::CurrentNinjaVersion() const
{
std::string version;
std::string command = ninjaCmd() + " --version";
@@ -1268,13 +1276,14 @@ std::string cmGlobalNinjaGenerator::ninjaVersion() const
&version, 0, 0, 0,
cmSystemTools::OUTPUT_NONE);
- return version;
+ return cmSystemTools::TrimWhitespace(version);
}
bool cmGlobalNinjaGenerator::SupportsConsolePool() const
{
return cmSystemTools::VersionCompare(cmSystemTools::OP_LESS,
- ninjaVersion().c_str(), "1.5") == false;
+ CurrentNinjaVersion().c_str(),
+ RequiredNinjaVersionForConsolePool().c_str()) == false;
}
void cmGlobalNinjaGenerator::WriteTargetClean(std::ostream& os)
diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h
index 2a749c1..f103801 100644
--- a/Source/cmGlobalNinjaGenerator.h
+++ b/Source/cmGlobalNinjaGenerator.h
@@ -289,7 +289,7 @@ public:
const std::vector<cmLocalGenerator*>& GetLocalGenerators() const {
return LocalGenerators; }
- bool IsExcluded(cmLocalGenerator* root, cmTarget& target) {
+ bool IsExcluded(cmLocalGenerator* root, cmGeneratorTarget* target) {
return cmGlobalGenerator::IsExcluded(root, target); }
int GetRuleCmdLength(const std::string& name) {
@@ -299,8 +299,10 @@ public:
virtual void ComputeTargetObjectDirectory(cmGeneratorTarget* gt) const;
- std::string ninjaVersion() const;
-
+ std::string CurrentNinjaVersion() const;
+ // Ninja generator uses 'deps' and 'msvc_deps_prefix' introduced in 1.3
+ static std::string RequiredNinjaVersion() { return "1.3"; }
+ static std::string RequiredNinjaVersionForConsolePool() { return "1.5"; }
bool SupportsConsolePool() const;
protected:
diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx
index edf2705..76d059ee 100644
--- a/Source/cmGlobalUnixMakefileGenerator3.cxx
+++ b/Source/cmGlobalUnixMakefileGenerator3.cxx
@@ -482,7 +482,7 @@ cmGlobalUnixMakefileGenerator3
// Add this to the list of depends rules in this directory.
if((!check_all || !gtarget->GetPropertyAsBool("EXCLUDE_FROM_ALL")) &&
(!check_relink ||
- gtarget->Target
+ gtarget
->NeedRelinkBeforeInstall(lg->GetConfigName())))
{
std::string tname = lg->GetRelativeTargetDirectory(*gtarget->Target);
@@ -691,7 +691,7 @@ cmGlobalUnixMakefileGenerator3
// Add a local name for the rule to relink the target before
// installation.
- if(gtarget->Target
+ if(gtarget
->NeedRelinkBeforeInstall(lg->GetConfigName()))
{
makeTargetName = lg->GetRelativeTargetDirectory(*gtarget->Target);
@@ -821,7 +821,7 @@ cmGlobalUnixMakefileGenerator3
localName, depends, commands, true);
// add the all/all dependency
- if(!this->IsExcluded(this->LocalGenerators[0], *gtarget->Target))
+ if(!this->IsExcluded(this->LocalGenerators[0], gtarget))
{
depends.clear();
depends.push_back(localName);
@@ -876,7 +876,7 @@ cmGlobalUnixMakefileGenerator3
name, depends, commands, true);
// Add rules to prepare the target for installation.
- if(gtarget->Target
+ if(gtarget
->NeedRelinkBeforeInstall(lg->GetConfigName()))
{
localName = lg->GetRelativeTargetDirectory(*gtarget->Target);
@@ -889,7 +889,7 @@ cmGlobalUnixMakefileGenerator3
"Pre-install relink rule for target.",
localName, depends, commands, true);
- if(!this->IsExcluded(this->LocalGenerators[0], *gtarget->Target))
+ if(!this->IsExcluded(this->LocalGenerators[0], gtarget))
{
depends.clear();
depends.push_back(localName);
diff --git a/Source/cmGlobalVisualStudio10Generator.cxx b/Source/cmGlobalVisualStudio10Generator.cxx
index 4e8ada4..8ec4fd9 100644
--- a/Source/cmGlobalVisualStudio10Generator.cxx
+++ b/Source/cmGlobalVisualStudio10Generator.cxx
@@ -314,9 +314,18 @@ cmGlobalVisualStudio10Generator::CreateLocalGenerator(cmLocalGenerator* parent,
}
//----------------------------------------------------------------------------
-void cmGlobalVisualStudio10Generator::Generate()
+bool cmGlobalVisualStudio10Generator::Compute()
{
+ if (!cmGlobalVisualStudio8Generator::Compute())
+ {
+ return false;
+ }
this->LongestSource = LongestSourcePath();
+ return true;
+}
+
+void cmGlobalVisualStudio10Generator::Generate()
+{
this->cmGlobalVisualStudio8Generator::Generate();
if(this->LongestSource.Length > 0)
{
diff --git a/Source/cmGlobalVisualStudio10Generator.h b/Source/cmGlobalVisualStudio10Generator.h
index 74d5022..3d34a3f 100644
--- a/Source/cmGlobalVisualStudio10Generator.h
+++ b/Source/cmGlobalVisualStudio10Generator.h
@@ -45,6 +45,8 @@ public:
std::vector<std::string> const& makeOptions = std::vector<std::string>()
);
+ virtual bool Compute();
+
///! create the correct local generator
virtual cmLocalGenerator *CreateLocalGenerator(cmLocalGenerator* parent,
cmState::Snapshot snapshot);
diff --git a/Source/cmGlobalVisualStudio8Generator.cxx b/Source/cmGlobalVisualStudio8Generator.cxx
index f3cf36e..51dcab0 100644
--- a/Source/cmGlobalVisualStudio8Generator.cxx
+++ b/Source/cmGlobalVisualStudio8Generator.cxx
@@ -254,6 +254,9 @@ bool cmGlobalVisualStudio8Generator::AddCheckTarget()
mf->AddUtilityCommand(CMAKE_CHECK_BUILD_SYSTEM_TARGET, false,
no_working_directory, no_depends,
noCommandLines);
+ tgt->Compute();
+ cmGeneratorTarget* gt = new cmGeneratorTarget(tgt, lg);
+ mf->AddGeneratorTarget(tgt, gt);
// Organize in the "predefined targets" folder:
//
@@ -345,8 +348,13 @@ bool cmGlobalVisualStudio8Generator::AddCheckTarget()
}
//----------------------------------------------------------------------------
-void cmGlobalVisualStudio8Generator::Generate()
+bool cmGlobalVisualStudio8Generator::Compute()
{
+ if (!cmGlobalVisualStudio7Generator::Compute())
+ {
+ return false;
+ }
+
if(this->AddCheckTarget())
{
// All targets depend on the build-system check target.
@@ -360,9 +368,7 @@ void cmGlobalVisualStudio8Generator::Generate()
}
}
}
-
- // Now perform the main generation.
- this->cmGlobalVisualStudio7Generator::Generate();
+ return true;
}
//----------------------------------------------------------------------------
diff --git a/Source/cmGlobalVisualStudio8Generator.h b/Source/cmGlobalVisualStudio8Generator.h
index cc02b78..1c61103 100644
--- a/Source/cmGlobalVisualStudio8Generator.h
+++ b/Source/cmGlobalVisualStudio8Generator.h
@@ -67,7 +67,7 @@ public:
return !this->WindowsCEVersion.empty(); }
protected:
- virtual void Generate();
+ virtual bool Compute();
virtual const char* GetIDEVersion() { return "8.0"; }
virtual std::string FindDevEnvCommand();
diff --git a/Source/cmGlobalVisualStudioGenerator.cxx b/Source/cmGlobalVisualStudioGenerator.cxx
index 1d583eb..c38a35a 100644
--- a/Source/cmGlobalVisualStudioGenerator.cxx
+++ b/Source/cmGlobalVisualStudioGenerator.cxx
@@ -64,8 +64,13 @@ std::string cmGlobalVisualStudioGenerator::GetRegistryBase(
}
//----------------------------------------------------------------------------
-void cmGlobalVisualStudioGenerator::Generate()
+bool cmGlobalVisualStudioGenerator::Compute()
{
+ if (!cmGlobalGenerator::Compute())
+ {
+ return false;
+ }
+
// Add a special target that depends on ALL projects for easy build
// of one configuration only.
const char* no_working_dir = 0;
@@ -85,6 +90,9 @@ void cmGlobalVisualStudioGenerator::Generate()
AddUtilityCommand("ALL_BUILD", true, no_working_dir,
no_depends, no_commands, false,
"Build all projects");
+ allBuild->Compute();
+ cmGeneratorTarget* gt = new cmGeneratorTarget(allBuild, gen[0]);
+ allBuild->GetMakefile()->AddGeneratorTarget(allBuild, gt);
#if 0
// Can't activate this code because we want ALL_BUILD
@@ -104,13 +112,19 @@ void cmGlobalVisualStudioGenerator::Generate()
for(std::vector<cmLocalGenerator*>::iterator i = gen.begin();
i != gen.end(); ++i)
{
- cmTargets& targets = (*i)->GetMakefile()->GetTargets();
- for(cmTargets::iterator t = targets.begin();
+ cmGeneratorTargetsType targets =
+ (*i)->GetMakefile()->GetGeneratorTargets();
+ for(cmGeneratorTargetsType::iterator t = targets.begin();
t != targets.end(); ++t)
{
+ if (t->second->GetType() == cmTarget::GLOBAL_TARGET
+ || t->first->IsImported())
+ {
+ continue;
+ }
if(!this->IsExcluded(gen[0], t->second))
{
- allBuild->AddUtility(t->second.GetName());
+ allBuild->AddUtility(t->second->GetName());
}
}
}
@@ -130,9 +144,7 @@ void cmGlobalVisualStudioGenerator::Generate()
static_cast<cmLocalVisualStudioGenerator*>(*lgi);
lg->AddCMakeListsRules();
}
-
- // Run all the local generators.
- this->cmGlobalGenerator::Generate();
+ return true;
}
//----------------------------------------------------------------------------
diff --git a/Source/cmGlobalVisualStudioGenerator.h b/Source/cmGlobalVisualStudioGenerator.h
index 8e2d6a4..64440ad 100644
--- a/Source/cmGlobalVisualStudioGenerator.h
+++ b/Source/cmGlobalVisualStudioGenerator.h
@@ -108,7 +108,7 @@ public:
cmGeneratorTarget*, std::vector<cmCustomCommand>& commands,
std::string const& configName);
protected:
- virtual void Generate();
+ virtual bool Compute();
// Does this VS version link targets to each other if there are
// dependencies in the SLN file? This was done for VS versions
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index ba5ff30..39933cb 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -378,8 +378,13 @@ cmGlobalXCodeGenerator::CreateLocalGenerator(cmLocalGenerator* parent,
}
//----------------------------------------------------------------------------
-void cmGlobalXCodeGenerator::Generate()
+bool cmGlobalXCodeGenerator::Compute()
{
+ if (!cmGlobalGenerator::Compute())
+ {
+ return false;
+ }
+
std::map<std::string, std::vector<cmLocalGenerator*> >::iterator it;
// make sure extra targets are added before calling
// the parent generate which will call trace depends
@@ -390,11 +395,17 @@ void cmGlobalXCodeGenerator::Generate()
// add ALL_BUILD, INSTALL, etc
this->AddExtraTargets(root, it->second);
}
+ return true;
+}
+
+void cmGlobalXCodeGenerator::Generate()
+{
this->cmGlobalGenerator::Generate();
if(cmSystemTools::GetErrorOccuredFlag())
{
return;
}
+ std::map<std::string, std::vector<cmLocalGenerator*> >::iterator it;
for(it = this->ProjectMap.begin(); it!= this->ProjectMap.end(); ++it)
{
cmLocalGenerator* root = it->second[0];
@@ -449,10 +460,12 @@ cmGlobalXCodeGenerator::AddExtraTargets(cmLocalGenerator* root,
// Add ALL_BUILD
const char* no_working_directory = 0;
std::vector<std::string> no_depends;
- mf->AddUtilityCommand("ALL_BUILD", true, no_depends,
+ cmTarget* allbuild = mf->AddUtilityCommand("ALL_BUILD", true, no_depends,
no_working_directory,
"echo", "Build all projects");
- cmTarget* allbuild = mf->FindTarget("ALL_BUILD");
+ allbuild->Compute();
+ cmGeneratorTarget* allBuildGt = new cmGeneratorTarget(allbuild, root);
+ mf->AddGeneratorTarget(allbuild, allBuildGt);
// Refer to the main build configuration file for easy editing.
std::string listfile = mf->GetCurrentSourceDirectory();
@@ -481,9 +494,13 @@ cmGlobalXCodeGenerator::AddExtraTargets(cmLocalGenerator* root,
std::string file = this->ConvertToRelativeForMake(
this->CurrentReRunCMakeMakefile.c_str());
cmSystemTools::ReplaceString(file, "\\ ", " ");
- mf->AddUtilityCommand(CMAKE_CHECK_BUILD_SYSTEM_TARGET, true, no_depends,
+ cmTarget* check = mf->AddUtilityCommand(CMAKE_CHECK_BUILD_SYSTEM_TARGET,
+ true, no_depends,
no_working_directory,
"make", "-f", file.c_str());
+ check->Compute();
+ cmGeneratorTarget* checkGt = new cmGeneratorTarget(check, root);
+ mf->AddGeneratorTarget(check, checkGt);
}
// now make the allbuild depend on all the non-utility targets
@@ -502,6 +519,11 @@ cmGlobalXCodeGenerator::AddExtraTargets(cmLocalGenerator* root,
{
cmTarget& target = l->second;
+ if (target.GetType() == cmTarget::GLOBAL_TARGET)
+ {
+ continue;
+ }
+
if (regenerate && (l->first != CMAKE_CHECK_BUILD_SYSTEM_TARGET))
{
target.AddUtility(CMAKE_CHECK_BUILD_SYSTEM_TARGET);
@@ -1356,7 +1378,8 @@ void cmGlobalXCodeGenerator::ForceLinkerLanguage(cmTarget& cmtarget)
return;
}
- std::string llang = cmtarget.GetLinkerLanguage("NOCONFIG");
+ cmGeneratorTarget *gtgt = this->GetGeneratorTarget(&cmtarget);
+ std::string llang = gtgt->GetLinkerLanguage("NOCONFIG");
if(llang.empty()) { return; }
// If the language is compiled as a source trust Xcode to link with it.
@@ -1804,7 +1827,8 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target,
AddCompileOptions(flags, &target, lang, configName);
}
- std::string llang = target.GetLinkerLanguage(configName);
+ cmGeneratorTarget *gtgt = this->GetGeneratorTarget(&target);
+ std::string llang = gtgt->GetLinkerLanguage(configName);
if(binary && llang.empty())
{
cmSystemTools::Error
@@ -1830,7 +1854,6 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target,
// Add the export symbol definition for shared library objects.
this->AppendDefines(ppDefs, exportMacro);
}
- cmGeneratorTarget *gtgt = this->GetGeneratorTarget(&target);
std::vector<std::string> targetDefines;
target.GetCompileDefinitions(targetDefines, configName, "C");
this->AppendDefines(ppDefs, targetDefines);
@@ -1920,11 +1943,11 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target,
std::string pnprefix;
std::string pnbase;
std::string pnsuffix;
- target.GetFullNameComponents(pnprefix, pnbase, pnsuffix, configName);
+ gtgt->GetFullNameComponents(pnprefix, pnbase, pnsuffix, configName);
const char* version = target.GetProperty("VERSION");
const char* soversion = target.GetProperty("SOVERSION");
- if(!target.HasSOName(configName) || target.IsFrameworkOnApple())
+ if(!gtgt->HasSOName(configName) || target.IsFrameworkOnApple())
{
version = 0;
soversion = 0;
@@ -2182,7 +2205,7 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target,
}
}
// Add framework search paths needed for linking.
- if(cmComputeLinkInformation* cli = target.GetLinkInformation(configName))
+ if(cmComputeLinkInformation* cli = gtgt->GetLinkInformation(configName))
{
std::vector<std::string> const& fwDirs = cli->GetFrameworkPaths();
for(std::vector<std::string>::const_iterator fdi = fwDirs.begin();
@@ -2311,7 +2334,7 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target,
if(target.GetType() == cmTarget::SHARED_LIBRARY)
{
// Get the install_name directory for the build tree.
- install_name_dir = target.GetInstallNameDirForBuildTree(configName);
+ install_name_dir = gtgt->GetInstallNameDirForBuildTree(configName);
// Xcode doesn't create the correct install_name in some cases.
// That is, if the INSTALL_PATH is empty, or if we have versioning
// of dylib libraries, we want to specify the install_name.
@@ -2325,7 +2348,7 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target,
install_name += install_name_dir;
install_name += "/";
}
- install_name += target.GetSOName(configName);
+ install_name += gtgt->GetSOName(configName);
if((realName != soName) || install_name_dir.empty())
{
@@ -2338,7 +2361,7 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target,
this->CreateString(install_name_dir.c_str()));
// Create the LD_RUNPATH_SEARCH_PATHS
- cmComputeLinkInformation* pcli = target.GetLinkInformation(configName);
+ cmComputeLinkInformation* pcli = gtgt->GetLinkInformation(configName);
if(pcli)
{
std::string search_paths;
@@ -2722,7 +2745,8 @@ cmGlobalXCodeGenerator::CreateXCodeTarget(cmTarget& cmtarget,
}
else
{
- fullName = cmtarget.GetFullName(defConfig.c_str());
+ cmGeneratorTarget *gtgt = this->GetGeneratorTarget(&cmtarget);
+ fullName = gtgt->GetFullName(defConfig.c_str());
}
fileRef->AddAttribute("path", this->CreateString(fullName.c_str()));
fileRef->AddAttribute("refType", this->CreateString("0"));
@@ -2944,7 +2968,8 @@ void cmGlobalXCodeGenerator
}
// Compute the link library and directory information.
- cmComputeLinkInformation* pcli = cmtarget->GetLinkInformation(configName);
+ cmGeneratorTarget* gtgt = this->GetGeneratorTarget(cmtarget);
+ cmComputeLinkInformation* pcli = gtgt->GetLinkInformation(configName);
if(!pcli)
{
continue;
@@ -3667,7 +3692,7 @@ cmGlobalXCodeGenerator::CreateXCodeDependHackTarget(
std::string universalFile = universal;
universalFile += *arch;
universalFile += "/";
- universalFile += t->GetFullName(configName);
+ universalFile += gt->GetFullName(configName);
makefileStream << "\t/bin/rm -f "
<<
this->ConvertToRelativeForMake(universalFile.c_str())
diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h
index c36e4af..ee8bf2c 100644
--- a/Source/cmGlobalXCodeGenerator.h
+++ b/Source/cmGlobalXCodeGenerator.h
@@ -88,6 +88,7 @@ public:
virtual bool SetGeneratorToolset(std::string const& ts, cmMakefile* mf);
void AppendFlag(std::string& flags, std::string const& flag);
protected:
+ virtual bool Compute();
virtual void Generate();
private:
cmXCodeObject* CreateOrGetPBXGroup(cmTarget& cmtarget,
diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx
index 899b088..f548f5d 100644
--- a/Source/cmInstallCommand.cxx
+++ b/Source/cmInstallCommand.cxx
@@ -27,7 +27,8 @@ static cmInstallTargetGenerator* CreateInstallTargetGenerator(cmTarget& target,
{
cmInstallGenerator::MessageLevel message =
cmInstallGenerator::SelectMessageLevel(target.GetMakefile());
- return new cmInstallTargetGenerator(target, args.GetDestination().c_str(),
+ return new cmInstallTargetGenerator(target.GetName(),
+ args.GetDestination().c_str(),
impLib, args.GetPermissions().c_str(),
args.GetConfigurations(), args.GetComponent().c_str(),
message,
@@ -752,6 +753,12 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
installsPublicHeader = installsPublicHeader || publicHeaderGenerator != 0;
installsResource = installsResource || resourceGenerator;
+ if (installsArchive || installsRuntime || installsFramework
+ || installsLibrary || installsBundle)
+ {
+ target.SetHaveInstallRule(true);
+ }
+
this->Makefile->AddInstallGenerator(archiveGenerator);
this->Makefile->AddInstallGenerator(libraryGenerator);
this->Makefile->AddInstallGenerator(runtimeGenerator);
diff --git a/Source/cmInstallGenerator.h b/Source/cmInstallGenerator.h
index c4191e4..b8e5b53 100644
--- a/Source/cmInstallGenerator.h
+++ b/Source/cmInstallGenerator.h
@@ -62,6 +62,8 @@ public:
/** Select message level from CMAKE_INSTALL_MESSAGE or 'never'. */
static MessageLevel SelectMessageLevel(cmMakefile* mf, bool never = false);
+ virtual void Compute(cmLocalGenerator*) {}
+
protected:
virtual void GenerateScript(std::ostream& os);
diff --git a/Source/cmInstallTargetGenerator.cxx b/Source/cmInstallTargetGenerator.cxx
index 5115788..30cf175 100644
--- a/Source/cmInstallTargetGenerator.cxx
+++ b/Source/cmInstallTargetGenerator.cxx
@@ -16,26 +16,30 @@
#include "cmGlobalGenerator.h"
#include "cmLocalGenerator.h"
#include "cmMakefile.h"
+#include "cmGeneratorTarget.h"
#include "cmake.h"
+#include "cmGeneratorTarget.h"
#include <assert.h>
//----------------------------------------------------------------------------
cmInstallTargetGenerator
-::cmInstallTargetGenerator(cmTarget& t, const char* dest, bool implib,
+::cmInstallTargetGenerator(const std::string& targetName,
+ const char* dest, bool implib,
const char* file_permissions,
std::vector<std::string> const& configurations,
const char* component,
MessageLevel message,
bool optional):
- cmInstallGenerator(dest, configurations, component, message), Target(&t),
+ cmInstallGenerator(dest, configurations, component, message),
+ TargetName(targetName),
+ Target(0),
FilePermissions(file_permissions),
ImportLibrary(implib),
Optional(optional)
{
this->ActionsPerConfig = true;
this->NamelinkMode = NamelinkModeNone;
- this->Target->SetHaveInstallRule(true);
}
//----------------------------------------------------------------------------
@@ -71,13 +75,15 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(std::ostream& os,
std::string fromDirConfig;
if(this->Target->NeedRelinkBeforeInstall(config))
{
- fromDirConfig = this->Target->GetMakefile()->GetCurrentBinaryDirectory();
+ fromDirConfig =
+ this->Target->Target->GetMakefile()->GetCurrentBinaryDirectory();
fromDirConfig += cmake::GetCMakeFilesDirectory();
fromDirConfig += "/CMakeRelink.dir/";
}
else
{
- fromDirConfig = this->Target->GetDirectory(config, this->ImportLibrary);
+ fromDirConfig =
+ this->Target->Target->GetDirectory(config, this->ImportLibrary);
fromDirConfig += "/";
}
std::string toDir =
@@ -88,7 +94,8 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(std::ostream& os,
std::vector<std::string> filesFrom;
std::vector<std::string> filesTo;
std::string literal_args;
- cmTarget::TargetType targetType = this->Target->GetType();
+ cmTarget::TargetType targetType =
+ static_cast<cmTarget::TargetType>(this->Target->GetType());
cmInstallType type = cmInstallType();
switch(targetType)
{
@@ -105,7 +112,7 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(std::ostream& os,
case cmTarget::UTILITY:
case cmTarget::GLOBAL_TARGET:
case cmTarget::UNKNOWN_LIBRARY:
- this->Target->GetMakefile()->IssueMessage(cmake::INTERNAL_ERROR,
+ this->Target->Target->GetMakefile()->IssueMessage(cmake::INTERNAL_ERROR,
"cmInstallTargetGenerator created with non-installable target.");
return;
}
@@ -128,7 +135,7 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(std::ostream& os,
filesFrom.push_back(from1);
filesTo.push_back(to1);
std::string targetNameImportLib;
- if(this->Target->GetImplibGNUtoMS(targetNameImport,
+ if(this->Target->Target->GetImplibGNUtoMS(targetNameImport,
targetNameImportLib))
{
filesFrom.push_back(fromDirConfig + targetNameImportLib);
@@ -144,7 +151,7 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(std::ostream& os,
std::string to1 = toDir + targetName;
// Handle OSX Bundles.
- if(this->Target->IsAppBundleOnApple())
+ if(this->Target->Target->IsAppBundleOnApple())
{
// Install the whole app bundle directory.
type = cmInstallType_DIRECTORY;
@@ -178,7 +185,8 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(std::ostream& os,
std::string targetNameReal;
std::string targetNameImport;
std::string targetNamePDB;
- this->Target->GetLibraryNames(targetName, targetNameSO, targetNameReal,
+ this->Target->GetLibraryNames(targetName, targetNameSO,
+ targetNameReal,
targetNameImport, targetNamePDB,
config);
if(this->ImportLibrary)
@@ -191,7 +199,7 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(std::ostream& os,
filesFrom.push_back(from1);
filesTo.push_back(to1);
std::string targetNameImportLib;
- if(this->Target->GetImplibGNUtoMS(targetNameImport,
+ if(this->Target->Target->GetImplibGNUtoMS(targetNameImport,
targetNameImportLib))
{
filesFrom.push_back(fromDirConfig + targetNameImportLib);
@@ -201,7 +209,7 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(std::ostream& os,
// An import library looks like a static library.
type = cmInstallType_STATIC_LIBRARY;
}
- else if(this->Target->IsFrameworkOnApple())
+ else if(this->Target->Target->IsFrameworkOnApple())
{
// There is a bug in cmInstallCommand if this fails.
assert(this->NamelinkMode == NamelinkModeNone);
@@ -219,7 +227,7 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(std::ostream& os,
filesFrom.push_back(from1);
filesTo.push_back(to1);
}
- else if(this->Target->IsCFBundleOnApple())
+ else if(this->Target->Target->IsCFBundleOnApple())
{
// Install the whole app bundle directory.
type = cmInstallType_DIRECTORY;
@@ -343,7 +351,7 @@ cmInstallTargetGenerator::GetDestination(std::string const& config) const
{
cmGeneratorExpression ge;
return ge.Parse(this->Destination)
- ->Evaluate(this->Target->GetMakefile(), config);
+ ->Evaluate(this->Target->Target->GetMakefile(), config);
}
//----------------------------------------------------------------------------
@@ -352,7 +360,7 @@ cmInstallTargetGenerator::GetInstallFilename(const std::string& config) const
{
NameType nameType = this->ImportLibrary? NameImplib : NameNormal;
return
- cmInstallTargetGenerator::GetInstallFilename(this->Target, config,
+ cmInstallTargetGenerator::GetInstallFilename(this->Target->Target, config,
nameType);
}
@@ -364,13 +372,16 @@ cmInstallTargetGenerator::GetInstallFilename(cmTarget const* target,
{
std::string fname;
// Compute the name of the library.
+ cmGeneratorTarget *gtgt = target->GetMakefile()
+ ->GetGlobalGenerator()
+ ->GetGeneratorTarget(target);
if(target->GetType() == cmTarget::EXECUTABLE)
{
std::string targetName;
std::string targetNameReal;
std::string targetNameImport;
std::string targetNamePDB;
- target->GetExecutableNames(targetName, targetNameReal,
+ gtgt->GetExecutableNames(targetName, targetNameReal,
targetNameImport, targetNamePDB,
config);
if(nameType == NameImplib)
@@ -400,7 +411,7 @@ cmInstallTargetGenerator::GetInstallFilename(cmTarget const* target,
std::string targetNameReal;
std::string targetNameImport;
std::string targetNamePDB;
- target->GetLibraryNames(targetName, targetNameSO, targetNameReal,
+ gtgt->GetLibraryNames(targetName, targetNameSO, targetNameReal,
targetNameImport, targetNamePDB, config);
if(nameType == NameImplib)
{
@@ -431,6 +442,12 @@ cmInstallTargetGenerator::GetInstallFilename(cmTarget const* target,
return fname;
}
+void cmInstallTargetGenerator::Compute(cmLocalGenerator* lg)
+{
+ this->Target = lg->GetGlobalGenerator()->GetGeneratorTarget(
+ lg->GetMakefile()->FindTarget(this->TargetName));
+}
+
//----------------------------------------------------------------------------
void
cmInstallTargetGenerator
@@ -533,8 +550,8 @@ cmInstallTargetGenerator
}
// Fix the install_name settings in installed binaries.
- std::string installNameTool =
- this->Target->GetMakefile()->GetSafeDefinition("CMAKE_INSTALL_NAME_TOOL");
+ std::string installNameTool = this->Target->Target->GetMakefile()
+ ->GetSafeDefinition("CMAKE_INSTALL_NAME_TOOL");
if(installNameTool.empty())
{
@@ -559,11 +576,14 @@ cmInstallTargetGenerator
continue;
}
+ cmGeneratorTarget *gtgt = tgt->GetMakefile()
+ ->GetGlobalGenerator()
+ ->GetGeneratorTarget(tgt);
// If the build tree and install tree use different path
// components of the install_name field then we need to create a
// mapping to be applied after installation.
- std::string for_build = tgt->GetInstallNameDirForBuildTree(config);
- std::string for_install = tgt->GetInstallNameDirForInstallTree();
+ std::string for_build = gtgt->GetInstallNameDirForBuildTree(config);
+ std::string for_install = gtgt->GetInstallNameDirForInstallTree();
if(for_build != for_install)
{
// The directory portions differ. Append the filename to
@@ -592,7 +612,7 @@ cmInstallTargetGenerator
std::string for_install =
this->Target->GetInstallNameDirForInstallTree();
- if(this->Target->IsFrameworkOnApple() && for_install.empty())
+ if(this->Target->Target->IsFrameworkOnApple() && for_install.empty())
{
// Frameworks seem to have an id corresponding to their own full
// path.
@@ -606,7 +626,7 @@ cmInstallTargetGenerator
{
// Prepare to refer to the install-tree install_name.
new_id = for_install;
- new_id += this->GetInstallFilename(this->Target, config, NameSO);
+ new_id += this->GetInstallFilename(this->Target->Target, config, NameSO);
}
}
@@ -643,9 +663,9 @@ cmInstallTargetGenerator
{
return;
}
-
// Skip if on Apple
- if(this->Target->GetMakefile()->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME"))
+ if(this->Target->Target->GetMakefile()
+ ->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME"))
{
return;
}
@@ -690,7 +710,7 @@ cmInstallTargetGenerator
return;
}
- cmMakefile* mf = this->Target->GetMakefile();
+ cmMakefile* mf = this->Target->Target->GetMakefile();
if(mf->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME"))
{
@@ -802,20 +822,20 @@ cmInstallTargetGenerator::AddStripRule(std::ostream& os,
}
// Don't handle OSX Bundles.
- if(this->Target->GetMakefile()->IsOn("APPLE") &&
- this->Target->GetPropertyAsBool("MACOSX_BUNDLE"))
+ if(this->Target->Target->GetMakefile()->IsOn("APPLE") &&
+ this->Target->Target->GetPropertyAsBool("MACOSX_BUNDLE"))
{
return;
}
- if(! this->Target->GetMakefile()->IsSet("CMAKE_STRIP"))
+ if(! this->Target->Target->GetMakefile()->IsSet("CMAKE_STRIP"))
{
return;
}
os << indent << "if(CMAKE_INSTALL_DO_STRIP)\n";
os << indent << " execute_process(COMMAND \""
- << this->Target->GetMakefile()->GetDefinition("CMAKE_STRIP")
+ << this->Target->Target->GetMakefile()->GetDefinition("CMAKE_STRIP")
<< "\" \"" << toDestDirPath << "\")\n";
os << indent << "endif()\n";
}
@@ -834,13 +854,13 @@ cmInstallTargetGenerator::AddRanlibRule(std::ostream& os,
// Perform post-installation processing on the file depending
// on its type.
- if(!this->Target->GetMakefile()->IsOn("APPLE"))
+ if(!this->Target->Target->GetMakefile()->IsOn("APPLE"))
{
return;
}
std::string ranlib =
- this->Target->GetMakefile()->GetRequiredDefinition("CMAKE_RANLIB");
+ this->Target->Target->GetMakefile()->GetRequiredDefinition("CMAKE_RANLIB");
if(ranlib.empty())
{
return;
diff --git a/Source/cmInstallTargetGenerator.h b/Source/cmInstallTargetGenerator.h
index db69220..a8f4a75 100644
--- a/Source/cmInstallTargetGenerator.h
+++ b/Source/cmInstallTargetGenerator.h
@@ -13,7 +13,9 @@
#define cmInstallTargetGenerator_h
#include "cmInstallGenerator.h"
-#include "cmTarget.h"
+
+class cmTarget;
+class cmGeneratorTarget;
/** \class cmInstallTargetGenerator
* \brief Generate target installation rules.
@@ -22,7 +24,7 @@ class cmInstallTargetGenerator: public cmInstallGenerator
{
public:
cmInstallTargetGenerator(
- cmTarget& t, const char* dest, bool implib,
+ std::string const& targetName, const char* dest, bool implib,
const char* file_permissions,
std::vector<std::string> const& configurations,
const char* component,
@@ -56,7 +58,10 @@ public:
const std::string& config,
NameType nameType = NameNormal);
- cmTarget* GetTarget() const { return this->Target; }
+ void Compute(cmLocalGenerator* lg);
+
+ cmGeneratorTarget* GetTarget() const { return this->Target; }
+
bool IsImportLibrary() const { return this->ImportLibrary; }
std::string GetDestination(std::string const& config) const;
@@ -98,7 +103,8 @@ protected:
void AddRanlibRule(std::ostream& os, Indent const& indent,
const std::string& toDestDirPath);
- cmTarget* Target;
+ std::string TargetName;
+ cmGeneratorTarget* Target;
std::string FilePermissions;
NamelinkModeType NamelinkMode;
bool ImportLibrary;
diff --git a/Source/cmLinkItem.h b/Source/cmLinkItem.h
new file mode 100644
index 0000000..a5427de
--- /dev/null
+++ b/Source/cmLinkItem.h
@@ -0,0 +1,59 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2004-2015 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmLinkItem_h
+#define cmLinkItem_h
+
+#include "cmListFileCache.h"
+
+class cmTarget;
+
+// Basic information about each link item.
+class cmLinkItem: public std::string
+{
+ typedef std::string std_string;
+public:
+ cmLinkItem(): std_string(), Target(0) {}
+ cmLinkItem(const std_string& n,
+ cmTarget const* t): std_string(n), Target(t) {}
+ cmLinkItem(cmLinkItem const& r): std_string(r), Target(r.Target) {}
+ cmTarget const* Target;
+};
+
+class cmLinkImplItem: public cmLinkItem
+{
+public:
+ cmLinkImplItem(): cmLinkItem(), Backtrace(), FromGenex(false) {}
+ cmLinkImplItem(std::string const& n,
+ cmTarget const* t,
+ cmListFileBacktrace const& bt,
+ bool fromGenex):
+ cmLinkItem(n, t), Backtrace(bt), FromGenex(fromGenex) {}
+ cmLinkImplItem(cmLinkImplItem const& r):
+ cmLinkItem(r), Backtrace(r.Backtrace), FromGenex(r.FromGenex) {}
+ cmListFileBacktrace Backtrace;
+ bool FromGenex;
+};
+
+/** The link implementation specifies the direct library
+ dependencies needed by the object files of the target. */
+struct cmLinkImplementationLibraries
+{
+ // Libraries linked directly in this configuration.
+ std::vector<cmLinkImplItem> Libraries;
+
+ // Libraries linked directly in other configurations.
+ // Needed only for OLD behavior of CMP0003.
+ std::vector<cmLinkItem> WrongConfigLibraries;
+};
+
+#endif
diff --git a/Source/cmLinkedTree.h b/Source/cmLinkedTree.h
index df00b30..3bcb940 100644
--- a/Source/cmLinkedTree.h
+++ b/Source/cmLinkedTree.h
@@ -155,6 +155,12 @@ public:
return iterator(this, 1);
}
+ void Clear()
+ {
+ this->UpPositions.clear();
+ this->Data.clear();
+ }
+
private:
T& GetReference(PositionType pos)
{
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx
index 2e20ee2..a831d88 100644
--- a/Source/cmLocalGenerator.cxx
+++ b/Source/cmLocalGenerator.cxx
@@ -16,6 +16,7 @@
#include "cmGlobalGenerator.h"
#include "cmInstallGenerator.h"
#include "cmInstallFilesGenerator.h"
+#include "cmGeneratorExpressionEvaluationFile.h"
#include "cmInstallScriptGenerator.h"
#include "cmInstallTargetGenerator.h"
#include "cmMakefile.h"
@@ -212,6 +213,53 @@ void cmLocalGenerator::GenerateTestFiles()
}
}
+void cmLocalGenerator::CreateEvaluationFileOutputs(std::string const& config)
+{
+ std::vector<cmGeneratorExpressionEvaluationFile*> ef =
+ this->Makefile->GetEvaluationFiles();
+ for(std::vector<cmGeneratorExpressionEvaluationFile*>::const_iterator
+ li = ef.begin(); li != ef.end(); ++li)
+ {
+ (*li)->CreateOutputFile(this, config);
+ }
+}
+
+void cmLocalGenerator::ProcessEvaluationFiles(
+ std::vector<std::string>& generatedFiles)
+{
+ std::vector<cmGeneratorExpressionEvaluationFile*> ef =
+ this->Makefile->GetEvaluationFiles();
+ for(std::vector<cmGeneratorExpressionEvaluationFile*>::const_iterator
+ li = ef.begin();
+ li != ef.end();
+ ++li)
+ {
+ (*li)->Generate(this);
+ if (cmSystemTools::GetFatalErrorOccured())
+ {
+ return;
+ }
+ std::vector<std::string> files = (*li)->GetFiles();
+ std::sort(files.begin(), files.end());
+
+ std::vector<std::string> intersection;
+ std::set_intersection(files.begin(), files.end(),
+ generatedFiles.begin(), generatedFiles.end(),
+ std::back_inserter(intersection));
+ if (!intersection.empty())
+ {
+ cmSystemTools::Error("Files to be generated by multiple different "
+ "commands: ", cmWrap('"', intersection, '"', " ").c_str());
+ return;
+ }
+
+ generatedFiles.insert(generatedFiles.end(), files.begin(), files.end());
+ std::vector<std::string>::iterator newIt =
+ generatedFiles.end() - files.size();
+ std::inplace_merge(generatedFiles.begin(), newIt, generatedFiles.end());
+ }
+}
+
//----------------------------------------------------------------------------
void cmLocalGenerator::GenerateInstallRules()
{
@@ -1353,7 +1401,7 @@ void cmLocalGenerator::GetTargetFlags(std::string& linkLibs,
linkFlags += this->Makefile->GetSafeDefinition(build);
linkFlags += " ";
}
- std::string linkLanguage = target->Target->GetLinkerLanguage(buildType);
+ std::string linkLanguage = target->GetLinkerLanguage(buildType);
if(linkLanguage.empty())
{
cmSystemTools::Error
@@ -1468,7 +1516,7 @@ void cmLocalGenerator::OutputLinkLibraries(std::string& linkLibraries,
bool escapeAllowMakeVars = !forResponseFile;
std::ostringstream fout;
std::string config = this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
- cmComputeLinkInformation* pcli = tgt.Target->GetLinkInformation(config);
+ cmComputeLinkInformation* pcli = tgt.GetLinkInformation(config);
if(!pcli)
{
return;
@@ -2059,7 +2107,9 @@ void cmLocalGenerator::AddCMP0018Flags(std::string &flags,
return;
}
- if (target->GetLinkInterfaceDependentBoolProperty(
+ cmGeneratorTarget* gtgt =
+ this->GlobalGenerator->GetGeneratorTarget(target);
+ if (gtgt->GetLinkInterfaceDependentBoolProperty(
"POSITION_INDEPENDENT_CODE",
config))
{
@@ -2375,11 +2425,15 @@ cmLocalGenerator::ConstructComment(cmCustomCommandGenerator const& ccg,
class cmInstallTargetGeneratorLocal: public cmInstallTargetGenerator
{
public:
- cmInstallTargetGeneratorLocal(cmTarget& t, const char* dest, bool implib):
+ cmInstallTargetGeneratorLocal(cmLocalGenerator* lg, std::string const& t,
+ const char* dest, bool implib):
cmInstallTargetGenerator(
t, dest, implib, "", std::vector<std::string>(), "Unspecified",
- cmInstallGenerator::SelectMessageLevel(t.GetMakefile()),
- false) {}
+ cmInstallGenerator::SelectMessageLevel(lg->GetMakefile()),
+ false)
+ {
+ this->Compute(lg);
+ }
};
//----------------------------------------------------------------------------
@@ -2428,7 +2482,7 @@ cmLocalGenerator
{
// Use a target install generator.
cmInstallTargetGeneratorLocal
- g(l->second, destination.c_str(), false);
+ g(this, l->first, destination.c_str(), false);
g.Generate(os, config, configurationTypes);
}
break;
@@ -2439,18 +2493,18 @@ cmLocalGenerator
// to the normal destination and the DLL to the runtime
// destination.
cmInstallTargetGeneratorLocal
- g1(l->second, destination.c_str(), true);
+ g1(this, l->first, destination.c_str(), true);
g1.Generate(os, config, configurationTypes);
// We also skip over the leading slash given by the user.
destination = l->second.GetRuntimeInstallPath().substr(1);
cmSystemTools::ConvertToUnixSlashes(destination);
cmInstallTargetGeneratorLocal
- g2(l->second, destination.c_str(), false);
+ g2(this, l->first, destination.c_str(), false);
g2.Generate(os, config, configurationTypes);
#else
// Use a target install generator.
cmInstallTargetGeneratorLocal
- g(l->second, destination.c_str(), false);
+ g(this, l->first, destination.c_str(), false);
g.Generate(os, config, configurationTypes);
#endif
}
diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h
index 2971574..1c18788 100644
--- a/Source/cmLocalGenerator.h
+++ b/Source/cmLocalGenerator.h
@@ -305,6 +305,8 @@ public:
void IssueMessage(cmake::MessageType t, std::string const& text) const;
+ void CreateEvaluationFileOutputs(const std::string& config);
+ void ProcessEvaluationFiles(std::vector<std::string>& generatedFiles);
void ComputeObjectMaxPath();
protected:
diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx
index 9889bd4..cfca418 100644
--- a/Source/cmLocalNinjaGenerator.cxx
+++ b/Source/cmLocalNinjaGenerator.cxx
@@ -90,7 +90,7 @@ void cmLocalNinjaGenerator::Generate()
// Add the target to "all" if required.
if (!this->GetGlobalNinjaGenerator()->IsExcluded(
this->GetGlobalNinjaGenerator()->GetLocalGenerators()[0],
- *t->second->Target))
+ t->second))
this->GetGlobalNinjaGenerator()->AddDependencyToAll(t->second->Target);
delete tg;
}
@@ -193,16 +193,14 @@ void cmLocalNinjaGenerator::WriteProjectHeader(std::ostream& os)
void cmLocalNinjaGenerator::WriteNinjaRequiredVersion(std::ostream& os)
{
// Default required version
- // Ninja generator uses 'deps' and 'msvc_deps_prefix' introduced in 1.3
- std::string requiredVersion = "1.3";
+ std::string requiredVersion =
+ this->GetGlobalNinjaGenerator()->RequiredNinjaVersion();
// Ninja generator uses the 'console' pool if available (>= 1.5)
- std::string usedVersion = this->GetGlobalNinjaGenerator()->ninjaVersion();
- if(cmSystemTools::VersionCompare(cmSystemTools::OP_LESS,
- usedVersion.c_str(),
- "1.5") == false)
+ if(this->GetGlobalNinjaGenerator()->SupportsConsolePool())
{
- requiredVersion = "1.5";
+ requiredVersion =
+ this->GetGlobalNinjaGenerator()->RequiredNinjaVersionForConsolePool();
}
cmGlobalNinjaGenerator::WriteComment(os,
diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx
index 98bd0ab..ce370bc 100644
--- a/Source/cmLocalUnixMakefileGenerator3.cxx
+++ b/Source/cmLocalUnixMakefileGenerator3.cxx
@@ -486,8 +486,7 @@ void cmLocalUnixMakefileGenerator3
// Add a local name for the rule to relink the target before
// installation.
- if(t->second->Target
- ->NeedRelinkBeforeInstall(this->ConfigName))
+ if(t->second->NeedRelinkBeforeInstall(this->ConfigName))
{
makeTargetName = this->GetRelativeTargetDirectory(*t->second->Target);
makeTargetName += "/preinstall";
diff --git a/Source/cmLocalVisualStudio6Generator.cxx b/Source/cmLocalVisualStudio6Generator.cxx
index f1c8def..29e1034 100644
--- a/Source/cmLocalVisualStudio6Generator.cxx
+++ b/Source/cmLocalVisualStudio6Generator.cxx
@@ -88,7 +88,8 @@ void cmLocalVisualStudio6Generator::AddCMakeListsRules()
for(cmTargets::iterator l = tgts.begin();
l != tgts.end(); l++)
{
- if (l->second.GetType() == cmTarget::INTERFACE_LIBRARY)
+ if (l->second.GetType() == cmTarget::INTERFACE_LIBRARY
+ || l->second.GetType() == cmTarget::GLOBAL_TARGET)
{
continue;
}
@@ -1114,10 +1115,12 @@ void cmLocalVisualStudio6Generator
cmTarget* tgt = this->GlobalGenerator->FindTarget(j->first.c_str());
if(tgt)
{
+ cmGeneratorTarget* gt =
+ this->GlobalGenerator->GetGeneratorTarget(tgt);
lib = cmSystemTools::GetFilenameWithoutExtension
- (tgt->GetFullName().c_str());
+ (gt->GetFullName().c_str());
libDebug = cmSystemTools::GetFilenameWithoutExtension
- (tgt->GetFullName("Debug").c_str());
+ (gt->GetFullName("Debug").c_str());
lib += ".lib";
libDebug += ".lib";
}
@@ -1257,8 +1260,8 @@ void cmLocalVisualStudio6Generator
extraLinkOptionsRelWithDebInfo += targetLinkFlags;
}
-
-
+ cmGeneratorTarget* gt =
+ this->GlobalGenerator->GetGeneratorTarget(&target);
// Get standard libraries for this language.
if(targetBuilds)
@@ -1267,10 +1270,10 @@ void cmLocalVisualStudio6Generator
std::vector<std::string> configs;
target.GetMakefile()->GetConfigurations(configs);
std::vector<std::string>::const_iterator it = configs.begin();
- const std::string& linkLanguage = target.GetLinkerLanguage(*it);
+ const std::string& linkLanguage = gt->GetLinkerLanguage(*it);
for ( ; it != configs.end(); ++it)
{
- const std::string& configLinkLanguage = target.GetLinkerLanguage(*it);
+ const std::string& configLinkLanguage = gt->GetLinkerLanguage(*it);
if (configLinkLanguage != linkLanguage)
{
cmSystemTools::Error
@@ -1327,11 +1330,11 @@ void cmLocalVisualStudio6Generator
target.GetType() == cmTarget::SHARED_LIBRARY ||
target.GetType() == cmTarget::MODULE_LIBRARY)
{
- outputName = target.GetFullName();
- outputNameDebug = target.GetFullName("Debug");
- outputNameRelease = target.GetFullName("Release");
- outputNameMinSizeRel = target.GetFullName("MinSizeRel");
- outputNameRelWithDebInfo = target.GetFullName("RelWithDebInfo");
+ outputName = gt->GetFullName();
+ outputNameDebug = gt->GetFullName("Debug");
+ outputNameRelease = gt->GetFullName("Release");
+ outputNameMinSizeRel = gt->GetFullName("MinSizeRel");
+ outputNameRelWithDebInfo = gt->GetFullName("RelWithDebInfo");
}
else if(target.GetType() == cmTarget::OBJECT_LIBRARY)
{
@@ -1428,10 +1431,10 @@ void cmLocalVisualStudio6Generator
fullPathImpRelease += "/";
fullPathImpMinSizeRel += "/";
fullPathImpRelWithDebInfo += "/";
- fullPathImpDebug += target.GetFullName("Debug", true);
- fullPathImpRelease += target.GetFullName("Release", true);
- fullPathImpMinSizeRel += target.GetFullName("MinSizeRel", true);
- fullPathImpRelWithDebInfo += target.GetFullName("RelWithDebInfo", true);
+ fullPathImpDebug += gt->GetFullName("Debug", true);
+ fullPathImpRelease += gt->GetFullName("Release", true);
+ fullPathImpMinSizeRel += gt->GetFullName("MinSizeRel", true);
+ fullPathImpRelWithDebInfo += gt->GetFullName("RelWithDebInfo", true);
targetImplibFlagDebug = "/implib:";
targetImplibFlagRelease = "/implib:";
@@ -1700,10 +1703,10 @@ void cmLocalVisualStudio6Generator
std::vector<std::string> configs;
target.GetMakefile()->GetConfigurations(configs);
std::vector<std::string>::const_iterator it = configs.begin();
- const std::string& linkLanguage = target.GetLinkerLanguage(*it);
+ const std::string& linkLanguage = gt->GetLinkerLanguage(*it);
for ( ; it != configs.end(); ++it)
{
- const std::string& configLinkLanguage = target.GetLinkerLanguage(*it);
+ const std::string& configLinkLanguage = gt->GetLinkerLanguage(*it);
if (configLinkLanguage != linkLanguage)
{
cmSystemTools::Error
@@ -1845,8 +1848,10 @@ void cmLocalVisualStudio6Generator
const std::string extraOptions,
std::string& options)
{
+ cmGeneratorTarget* gt =
+ this->GlobalGenerator->GetGeneratorTarget(&target);
// Compute the link information for this configuration.
- cmComputeLinkInformation* pcli = target.GetLinkInformation(configName);
+ cmComputeLinkInformation* pcli = gt->GetLinkInformation(configName);
if(!pcli)
{
return;
diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx
index f199a41..a38a061 100644
--- a/Source/cmLocalVisualStudio7Generator.cxx
+++ b/Source/cmLocalVisualStudio7Generator.cxx
@@ -108,6 +108,10 @@ void cmLocalVisualStudio7Generator::AddCMakeListsRules()
// Add the rule to targets that need it.
for(cmTargets::iterator l = tgts.begin(); l != tgts.end(); ++l)
{
+ if (l->second.GetType() == cmTarget::GLOBAL_TARGET)
+ {
+ continue;
+ }
if(l->first != CMAKE_CHECK_BUILD_SYSTEM_TARGET)
{
l->second.AddSource(sf->GetFullPath());
@@ -660,6 +664,10 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(std::ostream& fout,
const char* configType = "10";
const char* projectType = 0;
bool targetBuilds = true;
+
+ cmGeneratorTarget* gt =
+ this->GlobalGenerator->GetGeneratorTarget(&target);
+
switch(target.GetType())
{
case cmTarget::OBJECT_LIBRARY:
@@ -692,7 +700,7 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(std::ostream& fout,
{
const std::string& linkLanguage = (this->FortranProject?
std::string("Fortran"):
- target.GetLinkerLanguage(configName));
+ gt->GetLinkerLanguage(configName));
if(linkLanguage.empty())
{
cmSystemTools::Error
@@ -754,8 +762,6 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(std::ostream& fout,
targetOptions.Parse(flags.c_str());
targetOptions.Parse(defineFlags.c_str());
targetOptions.ParseFinish();
- cmGeneratorTarget* gt =
- this->GlobalGenerator->GetGeneratorTarget(&target);
std::vector<std::string> targetDefines;
target.GetCompileDefinitions(targetDefines, configName, "CXX");
targetOptions.AddDefines(targetDefines);
@@ -799,7 +805,7 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(std::ostream& fout,
if (this->FortranProject)
{
// Intel Fortran >= 15.0 uses TargetName property.
- std::string targetNameFull = target.GetFullName(configName);
+ std::string targetNameFull = gt->GetFullName(configName);
std::string targetName =
cmSystemTools::GetFilenameWithoutLastExtension(targetNameFull);
std::string targetExt =
@@ -877,7 +883,7 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(std::ostream& fout,
if(target.GetType() <= cmTarget::OBJECT_LIBRARY)
{
// Specify the compiler program database file if configured.
- std::string pdb = target.GetCompilePDBPath(configName);
+ std::string pdb = gt->GetCompilePDBPath(configName);
if(!pdb.empty())
{
fout << "\t\t\t\tProgramDataBaseFileName=\""
@@ -1070,6 +1076,9 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout,
this->ConvertToOutputFormat(this->ModuleDefinitionFile, SHELL);
linkOptions.AddFlag("ModuleDefinitionFile", defFile.c_str());
}
+ cmGeneratorTarget* gt =
+ this->GlobalGenerator->GetGeneratorTarget(&target);
+
if (target.GetType() == cmTarget::SHARED_LIBRARY &&
this->Makefile->IsOn("CMAKE_SUPPORT_WINDOWS_EXPORT_ALL_SYMBOLS"))
{
@@ -1100,7 +1109,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout,
}
case cmTarget::STATIC_LIBRARY:
{
- std::string targetNameFull = target.GetFullName(configName);
+ std::string targetNameFull = gt->GetFullName(configName);
std::string libpath = target.GetDirectory(configName);
libpath += "/";
libpath += targetNameFull;
@@ -1140,11 +1149,11 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout,
std::string targetNameFull;
std::string targetNameImport;
std::string targetNamePDB;
- target.GetLibraryNames(targetName, targetNameSO, targetNameFull,
+ gt->GetLibraryNames(targetName, targetNameSO, targetNameFull,
targetNameImport, targetNamePDB, configName);
// Compute the link library and directory information.
- cmComputeLinkInformation* pcli = target.GetLinkInformation(configName);
+ cmComputeLinkInformation* pcli = gt->GetLinkInformation(configName);
if(!pcli)
{
return;
@@ -1237,11 +1246,11 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout,
std::string targetNameFull;
std::string targetNameImport;
std::string targetNamePDB;
- target.GetExecutableNames(targetName, targetNameFull,
+ gt->GetExecutableNames(targetName, targetNameFull,
targetNameImport, targetNamePDB, configName);
// Compute the link library and directory information.
- cmComputeLinkInformation* pcli = target.GetLinkInformation(configName);
+ cmComputeLinkInformation* pcli = gt->GetLinkInformation(configName);
if(!pcli)
{
return;
@@ -1628,7 +1637,7 @@ cmLocalVisualStudio7GeneratorFCInfo
lg->GlobalGenerator->GetLanguageFromExtension
(sf.GetExtension().c_str());
const std::string& sourceLang = lg->GetSourceFileLanguage(sf);
- const std::string& linkLanguage = target.GetLinkerLanguage(i->c_str());
+ const std::string& linkLanguage = gt->GetLinkerLanguage(i->c_str());
bool needForceLang = false;
// source file does not match its extension language
if(lang != sourceLang)
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index 57e33df..85bc493 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -21,6 +21,7 @@
#include "cmState.h"
#include "cmOutputConverter.h"
#include "cmFunctionBlocker.h"
+#include "cmGeneratorExpressionEvaluationFile.h"
#include "cmListFileCache.h"
#include "cmCommandArgumentParserHelper.h"
#include "cmGeneratorExpression.h"
@@ -189,12 +190,12 @@ cmMakefile::cmMakefile(cmLocalGenerator* localGenerator)
this->cmAtVarRegex.compile("(@[A-Za-z_0-9/.+-]+@)");
this->cmNamedCurly.compile("^[A-Za-z0-9/_.+-]+{");
+ this->StateSnapshot = this->StateSnapshot.GetState()
+ ->CreatePolicyScopeSnapshot(this->StateSnapshot);
+
// Enter a policy level for this directory.
this->PushPolicy();
- // Protect the directory-level policies.
- this->PushPolicyBarrier();
-
// push empty loop block
this->PushLoopBlockBarrier();
@@ -235,12 +236,10 @@ cmMakefile::~cmMakefile()
cmDeleteAll(this->ImportedTargetsOwned);
cmDeleteAll(this->FinalPassCommands);
cmDeleteAll(this->FunctionBlockers);
+ cmDeleteAll(this->EvaluationFiles);
+ this->EvaluationFiles.clear();
+
this->FunctionBlockers.clear();
- if (this->PolicyStack.size() != 1)
- {
- cmSystemTools::Error("Internal CMake Error, Policy Stack has not been"
- " popped properly");
- }
}
//----------------------------------------------------------------------------
@@ -468,6 +467,14 @@ cmMakefile::IncludeScope::IncludeScope(cmMakefile* mf,
Makefile(mf), NoPolicyScope(noPolicyScope),
CheckCMP0011(false), ReportError(true)
{
+ this->Makefile->PushFunctionBlockerBarrier();
+
+ this->Makefile->StateSnapshot =
+ this->Makefile->GetState()->CreateCallStackSnapshot(
+ this->Makefile->StateSnapshot,
+ this->Makefile->ContextStack.back()->Name,
+ this->Makefile->ContextStack.back()->Line,
+ filenametoread);
if(!this->NoPolicyScope)
{
// Check CMP0011 to determine the policy scope type.
@@ -496,37 +503,19 @@ cmMakefile::IncludeScope::IncludeScope(cmMakefile* mf,
break;
}
}
-
- // The included file cannot pop our policy scope.
- this->Makefile->PushPolicyBarrier();
- this->Makefile->PushFunctionBlockerBarrier();
-
- this->Makefile->StateSnapshot =
- this->Makefile->GetState()->CreateCallStackSnapshot(
- this->Makefile->StateSnapshot,
- this->Makefile->ContextStack.back()->Name,
- this->Makefile->ContextStack.back()->Line,
- filenametoread);
}
//----------------------------------------------------------------------------
cmMakefile::IncludeScope::~IncludeScope()
{
- this->Makefile->StateSnapshot =
- this->Makefile->GetState()->Pop(this->Makefile->StateSnapshot);
- assert(this->Makefile->StateSnapshot.IsValid());
-
- this->Makefile->PopFunctionBlockerBarrier(this->ReportError);
- // Enforce matching policy scopes inside the included file.
- this->Makefile->PopPolicyBarrier(this->ReportError);
-
if(!this->NoPolicyScope)
{
// If we need to enforce policy CMP0011 then the top entry is the
// one we pushed above. If the entry is empty, then the included
// script did not set any policies that might affect the includer so
// we do not need to enforce the policy.
- if(this->CheckCMP0011 && this->Makefile->PolicyStack.back().IsEmpty())
+ if(this->CheckCMP0011
+ && !this->Makefile->StateSnapshot.HasDefinedPolicyCMP0011())
{
this->CheckCMP0011 = false;
}
@@ -541,6 +530,9 @@ cmMakefile::IncludeScope::~IncludeScope()
this->EnforceCMP0011();
}
}
+ this->Makefile->PopPolicyBarrier(this->ReportError);
+
+ this->Makefile->PopFunctionBlockerBarrier(this->ReportError);
}
//----------------------------------------------------------------------------
@@ -635,8 +627,6 @@ public:
ListFileScope(cmMakefile* mf, std::string const& filenametoread)
: Makefile(mf), ReportError(true)
{
- this->Makefile->PushPolicyBarrier();
-
long line = 0;
std::string name;
if (!this->Makefile->ContextStack.empty())
@@ -648,17 +638,14 @@ public:
this->Makefile->GetState()->CreateInlineListFileSnapshot(
this->Makefile->StateSnapshot, name, line, filenametoread);
assert(this->Makefile->StateSnapshot.IsValid());
+
this->Makefile->PushFunctionBlockerBarrier();
}
~ListFileScope()
{
- this->Makefile->StateSnapshot =
- this->Makefile->GetState()->Pop(this->Makefile->StateSnapshot);
- assert(this->Makefile->StateSnapshot.IsValid());
-
- this->Makefile->PopFunctionBlockerBarrier(this->ReportError);
this->Makefile->PopPolicyBarrier(this->ReportError);
+ this->Makefile->PopFunctionBlockerBarrier(this->ReportError);
}
void Quiet() { this->ReportError = false; }
@@ -777,6 +764,23 @@ void cmMakefile::EnforceDirectoryLevelRules() const
}
}
+void cmMakefile::AddEvaluationFile(const std::string& inputFile,
+ cmsys::auto_ptr<cmCompiledGeneratorExpression> outputName,
+ cmsys::auto_ptr<cmCompiledGeneratorExpression> condition,
+ bool inputIsContent)
+{
+ this->EvaluationFiles.push_back(
+ new cmGeneratorExpressionEvaluationFile(inputFile, outputName,
+ condition,
+ inputIsContent));
+}
+
+std::vector<cmGeneratorExpressionEvaluationFile*>
+cmMakefile::GetEvaluationFiles() const
+{
+ return this->EvaluationFiles;
+}
+
namespace
{
struct file_not_persistent
@@ -1205,15 +1209,16 @@ cmMakefile::AddCustomCommandOldStyle(const std::string& target,
}
//----------------------------------------------------------------------------
-void cmMakefile::AddUtilityCommand(const std::string& utilityName,
- bool excludeFromAll,
- const std::vector<std::string>& depends,
- const char* workingDirectory,
- const char* command,
- const char* arg1,
- const char* arg2,
- const char* arg3,
- const char* arg4)
+cmTarget*
+cmMakefile::AddUtilityCommand(const std::string& utilityName,
+ bool excludeFromAll,
+ const std::vector<std::string>& depends,
+ const char* workingDirectory,
+ const char* command,
+ const char* arg1,
+ const char* arg2,
+ const char* arg3,
+ const char* arg4)
{
// Construct the command line for the custom command.
cmCustomCommandLine commandLine;
@@ -1238,8 +1243,8 @@ void cmMakefile::AddUtilityCommand(const std::string& utilityName,
commandLines.push_back(commandLine);
// Call the real signature of this method.
- this->AddUtilityCommand(utilityName, excludeFromAll, workingDirectory,
- depends, commandLines);
+ return this->AddUtilityCommand(utilityName, excludeFromAll, workingDirectory,
+ depends, commandLines);
}
//----------------------------------------------------------------------------
@@ -1640,16 +1645,13 @@ void cmMakefile::PushFunctionScope(std::string const& fileName,
this->PushFunctionBlockerBarrier();
this->PushPolicy(true, pm);
- this->PushPolicyBarrier();
}
void cmMakefile::PopFunctionScope(bool reportError)
{
- this->PopPolicyBarrier(reportError);
this->PopPolicy();
- this->StateSnapshot = this->GetState()->Pop(this->StateSnapshot);
- assert(this->StateSnapshot.IsValid());
+ this->PopPolicyBarrier(reportError);
this->PopFunctionBlockerBarrier(reportError);
@@ -1677,16 +1679,12 @@ void cmMakefile::PushMacroScope(std::string const& fileName,
this->PushFunctionBlockerBarrier();
this->PushPolicy(true, pm);
- this->PushPolicyBarrier();
}
void cmMakefile::PopMacroScope(bool reportError)
{
- this->PopPolicyBarrier(reportError);
this->PopPolicy();
-
- this->StateSnapshot = this->GetState()->Pop(this->StateSnapshot);
- assert(this->StateSnapshot.IsValid());
+ this->PopPolicyBarrier(reportError);
this->PopFunctionBlockerBarrier(reportError);
}
@@ -1706,7 +1704,8 @@ public:
this->Makefile->StateSnapshot.GetDirectory().GetCurrentSource();
currentStart += "/CMakeLists.txt";
this->Makefile->StateSnapshot.SetListFile(currentStart);
- this->Makefile->PushPolicyBarrier();
+ this->Makefile->StateSnapshot = this->Makefile->StateSnapshot.GetState()
+ ->CreatePolicyScopeSnapshot(this->Makefile->StateSnapshot);
this->Makefile->PushFunctionBlockerBarrier();
this->GG = mf->GetGlobalGenerator();
@@ -1795,8 +1794,8 @@ void cmMakefile::ConfigureSubDirectory(cmMakefile *mf)
cmSystemTools::Message(msg.c_str());
}
- currentStart += "/CMakeLists.txt";
- if(!cmSystemTools::FileExists(currentStart.c_str(), true))
+ std::string const currentStartFile = currentStart + "/CMakeLists.txt";
+ if (!cmSystemTools::FileExists(currentStartFile, true))
{
// The file is missing. Check policy CMP0014.
std::ostringstream e;
@@ -1858,6 +1857,7 @@ void cmMakefile::AddSubDirectory(const std::string& srcPath,
// create a new local generator and set its parent
cmLocalGenerator *lg2 = this->GetGlobalGenerator()
->MakeLocalGenerator(newSnapshot, this->LocalGenerator);
+ this->GetGlobalGenerator()->AddMakefile(lg2->GetMakefile());
this->GetGlobalGenerator()->AddLocalGenerator(lg2);
cmMakefile* subMf = lg2->GetMakefile();
@@ -1905,6 +1905,12 @@ const char* cmMakefile::GetCurrentBinaryDirectory() const
return this->StateSnapshot.GetDirectory().GetCurrentBinary();
}
+void cmMakefile::AddGeneratorTarget(cmTarget* t, cmGeneratorTarget* gt)
+{
+ this->GeneratorTargets[t] = gt;
+ this->GetGlobalGenerator()->AddGeneratorTarget(t, gt);
+}
+
//----------------------------------------------------------------------------
void cmMakefile::AddIncludeDirectories(const std::vector<std::string> &incs,
bool before)
@@ -4747,30 +4753,7 @@ const char* cmMakefile::GetDefineFlagsCMP0059() const
cmPolicies::PolicyStatus
cmMakefile::GetPolicyStatus(cmPolicies::PolicyID id) const
{
- cmPolicies::PolicyStatus status = cmPolicies::GetPolicyStatus(id);
-
- if(status == cmPolicies::REQUIRED_ALWAYS ||
- status == cmPolicies::REQUIRED_IF_USED)
- {
- return status;
- }
-
- cmLocalGenerator* lg = this->LocalGenerator;
- while(lg)
- {
- cmMakefile const* mf = lg->GetMakefile();
- for(PolicyStackType::const_reverse_iterator psi =
- mf->PolicyStack.rbegin(); psi != mf->PolicyStack.rend(); ++psi)
- {
- if(psi->IsDefined(id))
- {
- status = psi->Get(id);
- return status;
- }
- }
- lg = lg->GetParent();
- }
- return status;
+ return this->StateSnapshot.GetPolicy(id);
}
//----------------------------------------------------------------------------
@@ -4819,15 +4802,7 @@ bool cmMakefile::SetPolicy(cmPolicies::PolicyID id,
return false;
}
- // Update the policy stack from the top to the top-most strong entry.
- bool previous_was_weak = true;
- for(PolicyStackType::reverse_iterator psi = this->PolicyStack.rbegin();
- previous_was_weak && psi != this->PolicyStack.rend(); ++psi)
- {
- psi->Set(id, status);
- previous_was_weak = psi->Weak;
- }
-
+ this->StateSnapshot.SetPolicy(id, status);
return true;
}
@@ -4836,32 +4811,28 @@ cmMakefile::PolicyPushPop::PolicyPushPop(cmMakefile* m, bool weak,
cmPolicies::PolicyMap const& pm):
Makefile(m), ReportError(true)
{
+ this->Makefile->StateSnapshot = this->Makefile->StateSnapshot.GetState()
+ ->CreatePolicyScopeSnapshot(this->Makefile->StateSnapshot);
this->Makefile->PushPolicy(weak, pm);
- this->Makefile->PushPolicyBarrier();
}
//----------------------------------------------------------------------------
cmMakefile::PolicyPushPop::~PolicyPushPop()
{
- this->Makefile->PopPolicyBarrier(this->ReportError);
this->Makefile->PopPolicy();
+ this->Makefile->PopPolicyBarrier(this->ReportError);
}
//----------------------------------------------------------------------------
void cmMakefile::PushPolicy(bool weak, cmPolicies::PolicyMap const& pm)
{
- // Allocate a new stack entry.
- this->PolicyStack.push_back(PolicyStackEntry(pm, weak));
+ this->StateSnapshot.PushPolicy(pm, weak);
}
//----------------------------------------------------------------------------
void cmMakefile::PopPolicy()
{
- if(this->PolicyStack.size() > this->PolicyBarriers.back())
- {
- this->PolicyStack.pop_back();
- }
- else
+ if (!this->StateSnapshot.PopPolicy())
{
this->IssueMessage(cmake::FATAL_ERROR,
"cmake_policy POP without matching PUSH");
@@ -4869,17 +4840,9 @@ void cmMakefile::PopPolicy()
}
//----------------------------------------------------------------------------
-void cmMakefile::PushPolicyBarrier()
-{
- this->PolicyBarriers.push_back(this->PolicyStack.size());
-}
-
-//----------------------------------------------------------------------------
void cmMakefile::PopPolicyBarrier(bool reportError)
{
- // Remove any extra entries pushed on the barrier.
- PolicyStackType::size_type barrier = this->PolicyBarriers.back();
- while(this->PolicyStack.size() > barrier)
+ while (!this->StateSnapshot.CanPopPolicyScope())
{
if(reportError)
{
@@ -4890,8 +4853,8 @@ void cmMakefile::PopPolicyBarrier(bool reportError)
this->PopPolicy();
}
- // Remove the barrier.
- this->PolicyBarriers.pop_back();
+ this->StateSnapshot = this->GetState()->Pop(this->StateSnapshot);
+ assert(this->StateSnapshot.IsValid());
}
//----------------------------------------------------------------------------
diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h
index 7938fcc..1c4da00 100644
--- a/Source/cmMakefile.h
+++ b/Source/cmMakefile.h
@@ -52,6 +52,7 @@ class cmVariableWatch;
class cmake;
class cmMakefileCall;
class cmCMakePolicyCommand;
+class cmGeneratorExpressionEvaluationFile;
/** \class cmMakefile
* \brief Process the input CMakeLists.txt file.
@@ -113,10 +114,6 @@ public:
bool GetIsSourceFileTryCompile() const;
- ///! Get the current makefile generator.
- cmLocalGenerator* GetLocalGenerator() const
- { return this->LocalGenerator;}
-
/**
* Help enforce global target name uniqueness.
*/
@@ -194,14 +191,15 @@ public:
* Add a utility to the build. A utiltity target is a command that
* is run every time the target is built.
*/
- void AddUtilityCommand(const std::string& utilityName, bool excludeFromAll,
- const std::vector<std::string>& depends,
- const char* workingDirectory,
- const char* command,
- const char* arg1=0,
- const char* arg2=0,
- const char* arg3=0,
- const char* arg4=0);
+ cmTarget* AddUtilityCommand(const std::string& utilityName,
+ bool excludeFromAll,
+ const std::vector<std::string>& depends,
+ const char* workingDirectory,
+ const char* command,
+ const char* arg1=0,
+ const char* arg2=0,
+ const char* arg3=0,
+ const char* arg4=0);
cmTarget* AddUtilityCommand(const std::string& utilityName,
bool excludeFromAll,
const char* workingDirectory,
@@ -416,10 +414,7 @@ public:
{
this->GeneratorTargets = targets;
}
- void AddGeneratorTarget(cmTarget* t, cmGeneratorTarget* gt)
- {
- this->GeneratorTargets[t] = gt;
- }
+ void AddGeneratorTarget(cmTarget* t, cmGeneratorTarget* gt);
cmTarget* FindTarget(const std::string& name,
bool excludeAliases = false) const;
@@ -801,6 +796,12 @@ public:
void EnforceDirectoryLevelRules() const;
+ void AddEvaluationFile(const std::string &inputFile,
+ cmsys::auto_ptr<cmCompiledGeneratorExpression> outputName,
+ cmsys::auto_ptr<cmCompiledGeneratorExpression> condition,
+ bool inputIsContent);
+ std::vector<cmGeneratorExpressionEvaluationFile*> GetEvaluationFiles() const;
+
protected:
// add link libraries and directories to the target
void AddGlobalLinkInformation(const std::string& name, cmTarget& target);
@@ -897,6 +898,8 @@ private:
std::vector<cmMakefile*> UnConfiguredDirectories;
+ std::vector<cmGeneratorExpressionEvaluationFile*> EvaluationFiles;
+
cmPropertyMap Properties;
std::vector<cmCommandContext const*> ContextStack;
@@ -911,7 +914,6 @@ private:
void PushPolicy(bool weak = false,
cmPolicies::PolicyMap const& pm = cmPolicies::PolicyMap());
void PopPolicy();
- void PushPolicyBarrier();
void PopPolicyBarrier(bool reportError = true);
friend class cmCMakePolicyCommand;
class IncludeScope;
@@ -921,18 +923,6 @@ private:
class BuildsystemFileScope;
friend class BuildsystemFileScope;
- // stack of policy settings
- struct PolicyStackEntry: public cmPolicies::PolicyMap
- {
- typedef cmPolicies::PolicyMap derived;
- PolicyStackEntry(bool w = false): derived(), Weak(w) {}
- PolicyStackEntry(derived const& d, bool w = false): derived(d), Weak(w) {}
- PolicyStackEntry(PolicyStackEntry const& r): derived(r), Weak(r.Weak) {}
- bool Weak;
- };
- typedef std::vector<PolicyStackEntry> PolicyStackType;
- PolicyStackType PolicyStack;
- std::vector<PolicyStackType::size_type> PolicyBarriers;
// CMP0053 == old
cmake::MessageType ExpandVariablesInStringOld(
diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx
index 416063f..ccb0974 100644
--- a/Source/cmMakefileExecutableTargetGenerator.cxx
+++ b/Source/cmMakefileExecutableTargetGenerator.cxx
@@ -25,7 +25,7 @@ cmMakefileExecutableTargetGenerator
cmMakefileTargetGenerator(target)
{
this->CustomCommandDriver = OnDepends;
- this->Target->GetExecutableNames(
+ this->GeneratorTarget->GetExecutableNames(
this->TargetNameOut, this->TargetNameReal, this->TargetNameImport,
this->TargetNamePDB, this->ConfigName);
@@ -58,7 +58,7 @@ void cmMakefileExecutableTargetGenerator::WriteRuleFiles()
// write the link rules
this->WriteExecutableRule(false);
- if(this->Target->NeedRelinkBeforeInstall(this->ConfigName))
+ if(this->GeneratorTarget->NeedRelinkBeforeInstall(this->ConfigName))
{
// Write rules to link an installable version of the target.
this->WriteExecutableRule(true);
@@ -94,7 +94,7 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
std::string targetNameReal;
std::string targetNameImport;
std::string targetNamePDB;
- this->Target->GetExecutableNames
+ this->GeneratorTarget->GetExecutableNames
(targetName, targetNameReal, targetNameImport, targetNamePDB,
this->ConfigName);
@@ -130,7 +130,7 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
}
std::string compilePdbOutputPath =
- this->Target->GetCompilePDBDirectory(this->ConfigName);
+ this->GeneratorTarget->GetCompilePDBDirectory(this->ConfigName);
cmSystemTools::MakeDirectory(compilePdbOutputPath.c_str());
std::string pdbOutputPath = this->Target->GetPDBDirectory(this->ConfigName);
@@ -161,7 +161,7 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
// Get the language to use for linking this executable.
std::string linkLanguage =
- this->Target->GetLinkerLanguage(this->ConfigName);
+ this->GeneratorTarget->GetLinkerLanguage(this->ConfigName);
// Make sure we have a link language.
if(linkLanguage.empty())
diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx
index 696dcc4..2f995e8 100644
--- a/Source/cmMakefileLibraryTargetGenerator.cxx
+++ b/Source/cmMakefileLibraryTargetGenerator.cxx
@@ -28,7 +28,7 @@ cmMakefileLibraryTargetGenerator
this->CustomCommandDriver = OnDepends;
if (this->Target->GetType() != cmTarget::INTERFACE_LIBRARY)
{
- this->Target->GetLibraryNames(
+ this->GeneratorTarget->GetLibraryNames(
this->TargetNameOut, this->TargetNameSO, this->TargetNameReal,
this->TargetNameImport, this->TargetNamePDB, this->ConfigName);
}
@@ -69,7 +69,7 @@ void cmMakefileLibraryTargetGenerator::WriteRuleFiles()
break;
case cmTarget::SHARED_LIBRARY:
this->WriteSharedLibraryRules(false);
- if(this->Target->NeedRelinkBeforeInstall(this->ConfigName))
+ if(this->GeneratorTarget->NeedRelinkBeforeInstall(this->ConfigName))
{
// Write rules to link an installable version of the target.
this->WriteSharedLibraryRules(true);
@@ -77,7 +77,7 @@ void cmMakefileLibraryTargetGenerator::WriteRuleFiles()
break;
case cmTarget::MODULE_LIBRARY:
this->WriteModuleLibraryRules(false);
- if(this->Target->NeedRelinkBeforeInstall(this->ConfigName))
+ if(this->GeneratorTarget->NeedRelinkBeforeInstall(this->ConfigName))
{
// Write rules to link an installable version of the target.
this->WriteModuleLibraryRules(true);
@@ -133,7 +133,7 @@ void cmMakefileLibraryTargetGenerator::WriteObjectLibraryRules()
void cmMakefileLibraryTargetGenerator::WriteStaticLibraryRules()
{
std::string linkLanguage =
- this->Target->GetLinkerLanguage(this->ConfigName);
+ this->GeneratorTarget->GetLinkerLanguage(this->ConfigName);
std::string linkRuleVar = "CMAKE_";
linkRuleVar += linkLanguage;
linkRuleVar += "_CREATE_STATIC_LIBRARY";
@@ -159,7 +159,7 @@ void cmMakefileLibraryTargetGenerator::WriteSharedLibraryRules(bool relink)
return;
}
std::string linkLanguage =
- this->Target->GetLinkerLanguage(this->ConfigName);
+ this->GeneratorTarget->GetLinkerLanguage(this->ConfigName);
std::string linkRuleVar = "CMAKE_";
linkRuleVar += linkLanguage;
linkRuleVar += "_CREATE_SHARED_LIBRARY";
@@ -183,7 +183,7 @@ void cmMakefileLibraryTargetGenerator::WriteSharedLibraryRules(bool relink)
void cmMakefileLibraryTargetGenerator::WriteModuleLibraryRules(bool relink)
{
std::string linkLanguage =
- this->Target->GetLinkerLanguage(this->ConfigName);
+ this->GeneratorTarget->GetLinkerLanguage(this->ConfigName);
std::string linkRuleVar = "CMAKE_";
linkRuleVar += linkLanguage;
linkRuleVar += "_CREATE_SHARED_MODULE";
@@ -206,7 +206,7 @@ void cmMakefileLibraryTargetGenerator::WriteModuleLibraryRules(bool relink)
void cmMakefileLibraryTargetGenerator::WriteFrameworkRules(bool relink)
{
std::string linkLanguage =
- this->Target->GetLinkerLanguage(this->ConfigName);
+ this->GeneratorTarget->GetLinkerLanguage(this->ConfigName);
std::string linkRuleVar = "CMAKE_";
linkRuleVar += linkLanguage;
linkRuleVar += "_CREATE_MACOSX_FRAMEWORK";
@@ -238,7 +238,7 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules
// Get the language to use for linking this library.
std::string linkLanguage =
- this->Target->GetLinkerLanguage(this->ConfigName);
+ this->GeneratorTarget->GetLinkerLanguage(this->ConfigName);
// Make sure we have a link language.
if(linkLanguage.empty())
@@ -266,7 +266,7 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules
std::string targetNameReal;
std::string targetNameImport;
std::string targetNamePDB;
- this->Target->GetLibraryNames(
+ this->GeneratorTarget->GetLibraryNames(
targetName, targetNameSO, targetNameReal, targetNameImport, targetNamePDB,
this->ConfigName);
@@ -311,7 +311,7 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules
}
std::string compilePdbOutputPath =
- this->Target->GetCompilePDBDirectory(this->ConfigName);
+ this->GeneratorTarget->GetCompilePDBDirectory(this->ConfigName);
cmSystemTools::MakeDirectory(compilePdbOutputPath.c_str());
std::string pdbOutputPath = this->Target->GetPDBDirectory(this->ConfigName);
@@ -653,7 +653,7 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules
vars.Target = target.c_str();
vars.LinkLibraries = linkLibs.c_str();
vars.ObjectsQuoted = buildObjs.c_str();
- if (this->Target->HasSOName(this->ConfigName))
+ if (this->GeneratorTarget->HasSOName(this->ConfigName))
{
vars.SONameFlag = this->Makefile->GetSONameFlag(linkLanguage);
vars.TargetSOName= targetNameSO.c_str();
@@ -666,7 +666,7 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules
{
// Get the install_name directory for the build tree.
install_name_dir =
- this->Target->GetInstallNameDirForBuildTree(this->ConfigName);
+ this->GeneratorTarget->GetInstallNameDirForBuildTree(this->ConfigName);
// Set the rule variable replacement value.
if(install_name_dir.empty())
diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx
index 0f82fb3..0b3df90 100644
--- a/Source/cmMakefileTargetGenerator.cxx
+++ b/Source/cmMakefileTargetGenerator.cxx
@@ -33,7 +33,7 @@
#include <ctype.h>
cmMakefileTargetGenerator::cmMakefileTargetGenerator(cmGeneratorTarget* target)
- : cmCommonTargetGenerator(target)
+ : cmCommonTargetGenerator(cmOutputConverter::START_OUTPUT, target)
, OSXBundleGenerator(0)
, MacOSXContentGenerator(0)
{
@@ -313,7 +313,7 @@ cmMakefileTargetGenerator::MacOSXContentGeneratorType::operator()
(cmSourceFile const& source, const char* pkgloc)
{
// Skip OS X content when not building a Framework or Bundle.
- if(!this->Generator->GetTarget()->IsBundleOnApple())
+ if(!this->Generator->GetGeneratorTarget()->IsBundleOnApple())
{
return;
}
@@ -414,7 +414,6 @@ void cmMakefileTargetGenerator
// we compute some depends when writing the depend.make that we will also
// use in the build.make, same with depMakeFile
std::vector<std::string> depends;
- std::string depMakeFile;
// generate the build rule file
this->WriteObjectBuildFile(obj, lang, source, depends);
@@ -549,12 +548,12 @@ cmMakefileTargetGenerator
this->GeneratorTarget->GetFullPath(this->ConfigName, false, true);
targetFullPathPDB = this->Target->GetPDBDirectory(this->ConfigName);
targetFullPathPDB += "/";
- targetFullPathPDB += this->Target->GetPDBName(this->ConfigName);
+ targetFullPathPDB += this->GeneratorTarget->GetPDBName(this->ConfigName);
}
if(this->Target->GetType() <= cmTarget::OBJECT_LIBRARY)
{
targetFullPathCompilePDB =
- this->Target->GetCompilePDBPath(this->ConfigName);
+ this->GeneratorTarget->GetCompilePDBPath(this->ConfigName);
if(targetFullPathCompilePDB.empty())
{
targetFullPathCompilePDB = this->Target->GetSupportDirectory() + "/";
@@ -1059,46 +1058,21 @@ void cmMakefileTargetGenerator::WriteTargetDependRules()
<< "\n"
<< "# Targets to which this target links.\n"
<< "set(CMAKE_TARGET_LINKED_INFO_FILES\n";
- std::set<cmTarget const*> emitted;
- const char* cfg = this->LocalGenerator->GetConfigName().c_str();
- if(cmComputeLinkInformation* cli = this->Target->GetLinkInformation(cfg))
+ std::vector<std::string> dirs = this->GetLinkedTargetDirectories();
+ for (std::vector<std::string>::iterator i = dirs.begin();
+ i != dirs.end(); ++i)
{
- cmComputeLinkInformation::ItemVector const& items = cli->GetItems();
- for(cmComputeLinkInformation::ItemVector::const_iterator
- i = items.begin(); i != items.end(); ++i)
- {
- cmTarget const* linkee = i->Target;
- if(linkee && !linkee->IsImported()
- // We can ignore the INTERFACE_LIBRARY items because
- // Target->GetLinkInformation already processed their
- // link interface and they don't have any output themselves.
- && linkee->GetType() != cmTarget::INTERFACE_LIBRARY
- && emitted.insert(linkee).second)
- {
- cmGeneratorTarget* gt =
- this->GlobalGenerator->GetGeneratorTarget(linkee);
- cmLocalGenerator* lg = gt->GetLocalGenerator();
- cmMakefile* mf = linkee->GetMakefile();
- std::string di = mf->GetCurrentBinaryDirectory();
- di += "/";
- di += lg->GetTargetDirectory(*linkee);
- di += "/DependInfo.cmake";
- *this->InfoFileStream << " \"" << di << "\"\n";
- }
- }
+ *this->InfoFileStream << " \"" << *i << "/DependInfo.cmake\"\n";
}
*this->InfoFileStream
<< " )\n";
}
- // Check for a target-specific module output directory.
- if(const char* mdir = this->GetFortranModuleDirectory())
- {
- *this->InfoFileStream
- << "\n"
- << "# Fortran module output directory.\n"
- << "set(CMAKE_Fortran_TARGET_MODULE_DIR \"" << mdir << "\")\n";
- }
+ *this->InfoFileStream
+ << "\n"
+ << "# Fortran module output directory.\n"
+ << "set(CMAKE_Fortran_TARGET_MODULE_DIR \""
+ << this->GetFortranModuleDirectory() << "\")\n";
// and now write the rule to use it
std::vector<std::string> depends;
@@ -1472,7 +1446,8 @@ void cmMakefileTargetGenerator
// Loop over all library dependencies.
const char* cfg = this->LocalGenerator->GetConfigName().c_str();
- if(cmComputeLinkInformation* cli = this->Target->GetLinkInformation(cfg))
+ if(cmComputeLinkInformation* cli =
+ this->GeneratorTarget->GetLinkInformation(cfg))
{
std::vector<std::string> const& libDeps = cli->GetDepends();
depends.insert(depends.end(), libDeps.begin(), libDeps.end());
@@ -1534,7 +1509,7 @@ std::string cmMakefileTargetGenerator::GetLinkRule(
if(this->Target->HasImplibGNUtoMS())
{
std::string ruleVar = "CMAKE_";
- ruleVar += this->Target->GetLinkerLanguage(this->ConfigName);
+ ruleVar += this->GeneratorTarget->GetLinkerLanguage(this->ConfigName);
ruleVar += "_GNUtoMS_RULE";
if(const char* rule = this->Makefile->GetDefinition(ruleVar))
{
@@ -1688,7 +1663,8 @@ cmMakefileTargetGenerator
{
// Lookup the response file reference flag.
std::string responseFlagVar = "CMAKE_";
- responseFlagVar += this->Target->GetLinkerLanguage(this->ConfigName);
+ responseFlagVar += this->GeneratorTarget
+ ->GetLinkerLanguage(this->ConfigName);
responseFlagVar += "_RESPONSE_FILE_LINK_FLAG";
const char* responseFlag =
this->Makefile->GetDefinition(responseFlagVar);
@@ -1732,7 +1708,8 @@ cmMakefileTargetGenerator
// Lookup the response file reference flag.
std::string responseFlagVar = "CMAKE_";
- responseFlagVar += this->Target->GetLinkerLanguage(this->ConfigName);
+ responseFlagVar += this->GeneratorTarget
+ ->GetLinkerLanguage(this->ConfigName);
responseFlagVar += "_RESPONSE_FILE_LINK_FLAG";
const char* responseFlag =
this->Makefile->GetDefinition(responseFlagVar);
diff --git a/Source/cmMakefileTargetGenerator.h b/Source/cmMakefileTargetGenerator.h
index b885672..fd4527b 100644
--- a/Source/cmMakefileTargetGenerator.h
+++ b/Source/cmMakefileTargetGenerator.h
@@ -53,6 +53,7 @@ public:
{ return this->ProgressFileNameFull; }
cmTarget* GetTarget() { return this->Target;}
+ cmGeneratorTarget* GetGeneratorTarget() { return this->GeneratorTarget;}
protected:
diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx
index 8ec6f5e..b855bea 100644
--- a/Source/cmNinjaNormalTargetGenerator.cxx
+++ b/Source/cmNinjaNormalTargetGenerator.cxx
@@ -40,16 +40,15 @@ cmNinjaNormalTargetGenerator(cmGeneratorTarget* target)
, TargetNamePDB()
, TargetLinkLanguage("")
{
- this->TargetLinkLanguage = target->Target
- ->GetLinkerLanguage(this->GetConfigName());
+ this->TargetLinkLanguage = target->GetLinkerLanguage(this->GetConfigName());
if (target->GetType() == cmTarget::EXECUTABLE)
- target->Target->GetExecutableNames(this->TargetNameOut,
+ this->GetGeneratorTarget()->GetExecutableNames(this->TargetNameOut,
this->TargetNameReal,
this->TargetNameImport,
this->TargetNamePDB,
GetLocalGenerator()->GetConfigName());
else
- target->Target->GetLibraryNames(this->TargetNameOut,
+ this->GetGeneratorTarget()->GetLibraryNames(this->TargetNameOut,
this->TargetNameSO,
this->TargetNameReal,
this->TargetNameImport,
@@ -531,13 +530,14 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement()
vars["LANGUAGE_COMPILE_FLAGS"] = t;
}
- if (target.HasSOName(cfgName))
+ if (this->GetGeneratorTarget()->HasSOName(cfgName))
{
vars["SONAME_FLAG"] = mf->GetSONameFlag(this->TargetLinkLanguage);
vars["SONAME"] = this->TargetNameSO;
if (targetType == cmTarget::SHARED_LIBRARY)
{
- std::string install_dir = target.GetInstallNameDirForBuildTree(cfgName);
+ std::string install_dir =
+ this->GetGeneratorTarget()->GetInstallNameDirForBuildTree(cfgName);
if (!install_dir.empty())
{
vars["INSTALLNAME_DIR"] = localGen.Convert(install_dir,
@@ -547,6 +547,8 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement()
}
}
+ cmNinjaDeps byproducts;
+
if (!this->TargetNameImport.empty())
{
const std::string impLibPath = localGen.ConvertToOutputFormat(
@@ -556,7 +558,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement()
EnsureParentDirectoryExists(impLibPath);
if(target.HasImportLibrary())
{
- outputs.push_back(targetOutputImplib);
+ byproducts.push_back(targetOutputImplib);
}
}
@@ -567,7 +569,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement()
std::string prefix;
std::string base;
std::string suffix;
- target.GetFullNameComponents(prefix, base, suffix);
+ this->GetGeneratorTarget()->GetFullNameComponents(prefix, base, suffix);
std::string dbg_suffix = ".dbg";
// TODO: Where to document?
if (mf->GetDefinition("CMAKE_DEBUG_SYMBOL_SUFFIX"))
@@ -602,7 +604,6 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement()
&postBuildCmdLines
};
- cmNinjaDeps byproducts;
for (unsigned i = 0; i != 3; ++i)
{
for (std::vector<cmCustomCommand>::const_iterator
diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx
index addf292..81fdde2 100644
--- a/Source/cmNinjaTargetGenerator.cxx
+++ b/Source/cmNinjaTargetGenerator.cxx
@@ -58,7 +58,7 @@ cmNinjaTargetGenerator::New(cmGeneratorTarget* target)
}
cmNinjaTargetGenerator::cmNinjaTargetGenerator(cmGeneratorTarget* target)
- : cmCommonTargetGenerator(target),
+ : cmCommonTargetGenerator(cmOutputConverter::HOME_OUTPUT, target),
MacOSXContentGenerator(0),
OSXBundleGenerator(0),
MacContentFolders(),
@@ -195,7 +195,7 @@ cmNinjaDeps cmNinjaTargetGenerator::ComputeLinkDeps() const
return cmNinjaDeps();
cmComputeLinkInformation* cli =
- this->Target->GetLinkInformation(this->GetConfigName());
+ this->GeneratorTarget->GetLinkInformation(this->GetConfigName());
if(!cli)
return cmNinjaDeps();
@@ -209,6 +209,15 @@ cmNinjaDeps cmNinjaTargetGenerator::ComputeLinkDeps() const
result.push_back(this->ConvertToNinjaPath(this->ModuleDefinitionFile));
}
+ // Add user-specified dependencies.
+ if (const char* linkDepends = this->Target->GetProperty("LINK_DEPENDS"))
+ {
+ std::vector<std::string> linkDeps;
+ cmSystemTools::ExpandListArgument(linkDepends, linkDeps);
+ std::transform(linkDeps.begin(), linkDeps.end(),
+ std::back_inserter(result), MapToNinjaPath());
+ }
+
return result;
}
@@ -273,11 +282,12 @@ bool cmNinjaTargetGenerator::SetMsvcTargetPdbVariable(cmNinjaVars& vars) const
{
pdbPath = this->Target->GetPDBDirectory(this->GetConfigName());
pdbPath += "/";
- pdbPath += this->Target->GetPDBName(this->GetConfigName());
+ pdbPath += this->GeneratorTarget->GetPDBName(this->GetConfigName());
}
if(this->Target->GetType() <= cmTarget::OBJECT_LIBRARY)
{
- compilePdbPath = this->Target->GetCompilePDBPath(this->GetConfigName());
+ compilePdbPath =
+ this->GeneratorTarget->GetCompilePDBPath(this->GetConfigName());
if(compilePdbPath.empty())
{
compilePdbPath = this->Target->GetSupportDirectory() + "/";
@@ -741,7 +751,7 @@ cmNinjaTargetGenerator::MacOSXContentGeneratorType::operator()(
cmSourceFile const& source, const char* pkgloc)
{
// Skip OS X content when not building a Framework or Bundle.
- if(!this->Generator->GetTarget()->IsBundleOnApple())
+ if(!this->Generator->GetGeneratorTarget()->IsBundleOnApple())
{
return;
}
diff --git a/Source/cmOSXBundleGenerator.cxx b/Source/cmOSXBundleGenerator.cxx
index 3bc0eb7..4fe99e3 100644
--- a/Source/cmOSXBundleGenerator.cxx
+++ b/Source/cmOSXBundleGenerator.cxx
@@ -47,7 +47,7 @@ void cmOSXBundleGenerator::CreateAppBundle(const std::string& targetName,
// Compute bundle directory names.
std::string out = outpath;
out += "/";
- out += this->GT->Target->GetAppBundleDirectory(this->ConfigName, false);
+ out += this->GT->GetAppBundleDirectory(this->ConfigName, false);
cmSystemTools::MakeDirectory(out.c_str());
this->Makefile->AddCMakeOutputFile(out);
@@ -57,7 +57,7 @@ void cmOSXBundleGenerator::CreateAppBundle(const std::string& targetName,
// to be set.
std::string plist = outpath;
plist += "/";
- plist += this->GT->Target->GetAppBundleDirectory(this->ConfigName, true);
+ plist += this->GT->GetAppBundleDirectory(this->ConfigName, true);
plist += "/Info.plist";
this->LocalGenerator->GenerateAppleInfoPList(this->GT->Target,
targetName,
@@ -77,11 +77,11 @@ void cmOSXBundleGenerator::CreateFramework(
// Compute the location of the top-level foo.framework directory.
std::string contentdir = outpath + "/" +
- this->GT->Target->GetFrameworkDirectory(this->ConfigName, true);
+ this->GT->GetFrameworkDirectory(this->ConfigName, true);
contentdir += "/";
std::string newoutpath = outpath + "/" +
- this->GT->Target->GetFrameworkDirectory(this->ConfigName, false);
+ this->GT->GetFrameworkDirectory(this->ConfigName, false);
std::string frameworkVersion = this->GT->Target->GetFrameworkVersion();
@@ -172,14 +172,14 @@ void cmOSXBundleGenerator::CreateCFBundle(const std::string& targetName,
// Compute bundle directory names.
std::string out = root;
out += "/";
- out += this->GT->Target->GetCFBundleDirectory(this->ConfigName, false);
+ out += this->GT->GetCFBundleDirectory(this->ConfigName, false);
cmSystemTools::MakeDirectory(out.c_str());
this->Makefile->AddCMakeOutputFile(out);
// Configure the Info.plist file. Note that it needs the executable name
// to be set.
std::string plist = root + "/" +
- this->GT->Target->GetCFBundleDirectory(this->ConfigName, true);
+ this->GT->GetCFBundleDirectory(this->ConfigName, true);
plist += "/Info.plist";
std::string name = cmSystemTools::GetFilenameName(targetName);
this->LocalGenerator->GenerateAppleInfoPList(this->GT->Target,
@@ -217,7 +217,7 @@ cmOSXBundleGenerator::InitMacOSXContentDirectory(const char* pkgloc)
// Construct the full path to the content subdirectory.
std::string macdir =
- this->GT->Target->GetMacContentDirectory(this->ConfigName,
+ this->GT->GetMacContentDirectory(this->ConfigName,
/*implib*/ false);
macdir += "/";
macdir += pkgloc;
diff --git a/Source/cmOrderDirectories.cxx b/Source/cmOrderDirectories.cxx
index a612437..35ee127 100644
--- a/Source/cmOrderDirectories.cxx
+++ b/Source/cmOrderDirectories.cxx
@@ -280,7 +280,7 @@ bool cmOrderDirectoriesConstraintLibrary::FindConflict(std::string const& dir)
//----------------------------------------------------------------------------
cmOrderDirectories::cmOrderDirectories(cmGlobalGenerator* gg,
- cmTarget const* target,
+ const cmGeneratorTarget* target,
const char* purpose)
{
this->GlobalGenerator = gg;
@@ -554,7 +554,8 @@ void cmOrderDirectories::FindImplicitConflicts()
<< text
<< "Some of these libraries may not be found correctly.";
this->GlobalGenerator->GetCMakeInstance()
- ->IssueMessage(cmake::WARNING, w.str(), this->Target->GetBacktrace());
+ ->IssueMessage(cmake::WARNING, w.str(),
+ this->Target->Target->GetBacktrace());
}
//----------------------------------------------------------------------------
@@ -635,5 +636,6 @@ void cmOrderDirectories::DiagnoseCycle()
}
e << "Some of these libraries may not be found correctly.";
this->GlobalGenerator->GetCMakeInstance()
- ->IssueMessage(cmake::WARNING, e.str(), this->Target->GetBacktrace());
+ ->IssueMessage(cmake::WARNING, e.str(),
+ this->Target->Target->GetBacktrace());
}
diff --git a/Source/cmOrderDirectories.h b/Source/cmOrderDirectories.h
index cb5a51f..211c786 100644
--- a/Source/cmOrderDirectories.h
+++ b/Source/cmOrderDirectories.h
@@ -19,7 +19,7 @@
class cmGlobalGenerator;
class cmOrderDirectoriesConstraint;
class cmOrderDirectoriesConstraintLibrary;
-class cmTarget;
+class cmGeneratorTarget;
/** \class cmOrderDirectories
* \brief Compute a safe runtime path order for a set of shared libraries.
@@ -27,7 +27,7 @@ class cmTarget;
class cmOrderDirectories
{
public:
- cmOrderDirectories(cmGlobalGenerator* gg, cmTarget const* target,
+ cmOrderDirectories(cmGlobalGenerator* gg, cmGeneratorTarget const* target,
const char* purpose);
~cmOrderDirectories();
void AddRuntimeLibrary(std::string const& fullPath, const char* soname = 0);
@@ -41,7 +41,7 @@ public:
std::vector<std::string> const& GetOrderedDirectories();
private:
cmGlobalGenerator* GlobalGenerator;
- cmTarget const* Target;
+ cmGeneratorTarget const* Target;
std::string Purpose;
std::vector<std::string> OrderedDirectories;
diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h
index b783701..a791b89 100644
--- a/Source/cmPolicies.h
+++ b/Source/cmPolicies.h
@@ -217,6 +217,9 @@ class cmPolicy;
3, 3, 0, cmPolicies::WARN) \
SELECT(POLICY, CMP0063, \
"Honor visibility properties for all target types.", \
+ 3, 3, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0064, \
+ "Support new TEST if() operator.", \
3, 3, 0, cmPolicies::WARN)
#define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
diff --git a/Source/cmQtAutoGenerators.cxx b/Source/cmQtAutoGenerators.cxx
index 979db91..4eb9b13 100644
--- a/Source/cmQtAutoGenerators.cxx
+++ b/Source/cmQtAutoGenerators.cxx
@@ -369,7 +369,7 @@ bool cmQtAutoGenerators::InitializeAutogenTarget(cmLocalGenerator* lg,
#if defined(_WIN32) && !defined(__CYGWIN__)
bool usePRE_BUILD = false;
- cmGlobalGenerator* gg = makefile->GetGlobalGenerator();
+ cmGlobalGenerator* gg = lg->GetGlobalGenerator();
if(gg->GetName().find("Visual Studio") != std::string::npos)
{
cmGlobalVisualStudioGenerator* vsgg =
@@ -396,7 +396,7 @@ bool cmQtAutoGenerators::InitializeAutogenTarget(cmLocalGenerator* lg,
std::vector<std::string> rcc_output;
bool const isNinja =
- makefile->GetGlobalGenerator()->GetName() == "Ninja";
+ lg->GetGlobalGenerator()->GetName() == "Ninja";
if(isNinja
#if defined(_WIN32) && !defined(__CYGWIN__)
|| usePRE_BUILD
@@ -475,8 +475,9 @@ bool cmQtAutoGenerators::InitializeAutogenTarget(cmLocalGenerator* lg,
/*byproducts=*/rcc_output, depends,
commandLines, false, autogenComment.c_str());
+ autogenTarget->Compute();
+
cmGeneratorTarget* gt = new cmGeneratorTarget(autogenTarget, lg);
- lg->GetGlobalGenerator()->AddGeneratorTarget(autogenTarget, gt);
makefile->AddGeneratorTarget(autogenTarget, gt);
// Set target folder
@@ -548,8 +549,11 @@ void cmQtAutoGenerators::SetupAutoGenerateTarget(cmTarget const* target)
{
qtVersion = makefile->GetDefinition("QT_VERSION_MAJOR");
}
+ cmGeneratorTarget *gtgt = target->GetMakefile()
+ ->GetGlobalGenerator()
+ ->GetGeneratorTarget(target);
if (const char *targetQtVersion =
- target->GetLinkInterfaceDependentStringProperty("QT_MAJOR_VERSION", ""))
+ gtgt->GetLinkInterfaceDependentStringProperty("QT_MAJOR_VERSION", ""))
{
qtVersion = targetQtVersion;
}
@@ -879,8 +883,11 @@ void cmQtAutoGenerators::MergeUicOptions(std::vector<std::string> &opts,
static void GetUicOpts(cmTarget const* target, const std::string& config,
std::string &optString)
{
+ cmGeneratorTarget *gtgt = target->GetMakefile()
+ ->GetGlobalGenerator()
+ ->GetGeneratorTarget(target);
std::vector<std::string> opts;
- target->GetAutoUicOptions(opts, config);
+ gtgt->GetAutoUicOptions(opts, config);
optString = cmJoin(opts, ";");
}
@@ -1148,6 +1155,9 @@ void cmQtAutoGenerators::SetupAutoRccTarget(cmTarget const* target)
std::string cmQtAutoGenerators::GetRccExecutable(cmTarget const* target)
{
+ cmGeneratorTarget *gtgt = target->GetMakefile()
+ ->GetGlobalGenerator()
+ ->GetGeneratorTarget(target);
cmMakefile *makefile = target->GetMakefile();
const char *qtVersion = makefile->GetDefinition("_target_qt_version");
if (!qtVersion)
@@ -1158,8 +1168,7 @@ std::string cmQtAutoGenerators::GetRccExecutable(cmTarget const* target)
qtVersion = makefile->GetDefinition("QT_VERSION_MAJOR");
}
if (const char *targetQtVersion =
- target->GetLinkInterfaceDependentStringProperty("QT_MAJOR_VERSION",
- ""))
+ gtgt->GetLinkInterfaceDependentStringProperty("QT_MAJOR_VERSION", ""))
{
qtVersion = targetQtVersion;
}
diff --git a/Source/cmScriptGenerator.h b/Source/cmScriptGenerator.h
index 9ab04f1..bc9372f 100644
--- a/Source/cmScriptGenerator.h
+++ b/Source/cmScriptGenerator.h
@@ -54,9 +54,6 @@ public:
void Generate(std::ostream& os, const std::string& config,
std::vector<std::string> const& configurationTypes);
- const std::vector<std::string>& GetConfigurations() const
- { return this->Configurations; }
-
protected:
typedef cmScriptGeneratorIndent Indent;
virtual void GenerateScript(std::ostream& os);
diff --git a/Source/cmSetPropertyCommand.cxx b/Source/cmSetPropertyCommand.cxx
index 31e460f..17ad475 100644
--- a/Source/cmSetPropertyCommand.cxx
+++ b/Source/cmSetPropertyCommand.cxx
@@ -205,14 +205,8 @@ bool cmSetPropertyCommand::HandleDirectoryMode()
// The local generators are associated with collapsed paths.
dir = cmSystemTools::CollapseFullPath(dir);
- // Lookup the generator.
- if(cmLocalGenerator* lg =
- this->Makefile->GetGlobalGenerator()->FindLocalGenerator(dir))
- {
- // Use the makefile for the directory found.
- mf = lg->GetMakefile();
- }
- else
+ mf = this->Makefile->GetGlobalGenerator()->FindMakefile(dir);
+ if (!mf)
{
// Could not find the directory.
this->SetError
diff --git a/Source/cmState.cxx b/Source/cmState.cxx
index d8f8306..f425861 100644
--- a/Source/cmState.cxx
+++ b/Source/cmState.cxx
@@ -20,8 +20,10 @@
struct cmState::SnapshotDataType
{
- cmState::PositionType CallStackParent;
cmState::PositionType DirectoryParent;
+ cmLinkedTree<cmState::PolicyStackEntry>::iterator Policies;
+ cmLinkedTree<cmState::PolicyStackEntry>::iterator PolicyRoot;
+ cmLinkedTree<cmState::PolicyStackEntry>::iterator PolicyScope;
cmState::SnapshotType SnapshotType;
cmLinkedTree<std::string>::iterator ExecutionListFile;
cmLinkedTree<cmState::BuildsystemDirectoryStateType>::iterator
@@ -33,8 +35,19 @@ struct cmState::SnapshotDataType
std::vector<std::string>::size_type CompileOptionsPosition;
};
+struct cmState::PolicyStackEntry: public cmPolicies::PolicyMap
+{
+ typedef cmPolicies::PolicyMap derived;
+ PolicyStackEntry(bool w = false): derived(), Weak(w) {}
+ PolicyStackEntry(derived const& d, bool w): derived(d), Weak(w) {}
+ PolicyStackEntry(PolicyStackEntry const& r): derived(r), Weak(r.Weak) {}
+ bool Weak;
+};
+
struct cmState::BuildsystemDirectoryStateType
{
+ cmState::PositionType DirectoryEnd;
+
std::string Location;
std::string OutputLocation;
@@ -240,6 +253,9 @@ cmState::Snapshot cmState::Reset()
this->GlobalProperties.clear();
this->PropertyDefinitions.clear();
+ PositionType pos = this->SnapshotData.Truncate();
+ this->ExecutionListFiles.Truncate();
+
{
cmLinkedTree<BuildsystemDirectoryStateType>::iterator it =
this->BuildsystemDirectory.Truncate();
@@ -249,9 +265,15 @@ cmState::Snapshot cmState::Reset()
it->CompileDefinitionsBacktraces.clear();
it->CompileOptions.clear();
it->CompileOptionsBacktraces.clear();
+ it->DirectoryEnd = pos;
}
- PositionType pos = this->SnapshotData.Truncate();
- this->ExecutionListFiles.Truncate();
+
+ this->PolicyStack.Clear();
+ pos->Policies = this->PolicyStack.Root();
+ pos->PolicyRoot = this->PolicyStack.Root();
+ pos->PolicyScope = this->PolicyStack.Root();
+ assert(pos->Policies.IsValid());
+ assert(pos->PolicyRoot.IsValid());
this->DefineProperty
("RULE_LAUNCH_COMPILE", cmProperty::DIRECTORY,
@@ -722,6 +744,12 @@ cmState::Snapshot cmState::CreateBaseSnapshot()
pos->IncludeDirectoryPosition = 0;
pos->CompileDefinitionsPosition = 0;
pos->CompileOptionsPosition = 0;
+ pos->BuildSystemDirectory->DirectoryEnd = pos;
+ pos->Policies = this->PolicyStack.Root();
+ pos->PolicyRoot = this->PolicyStack.Root();
+ pos->PolicyScope = this->PolicyStack.Root();
+ assert(pos->Policies.IsValid());
+ assert(pos->PolicyRoot.IsValid());
return cmState::Snapshot(this, pos);
}
@@ -732,7 +760,6 @@ cmState::CreateBuildsystemDirectorySnapshot(Snapshot originSnapshot,
{
assert(originSnapshot.IsValid());
PositionType pos = this->SnapshotData.Extend(originSnapshot.Position);
- pos->CallStackParent = originSnapshot.Position;
pos->EntryPointLine = entryPointLine;
pos->EntryPointCommand = entryPointCommand;
pos->DirectoryParent = originSnapshot.Position;
@@ -743,6 +770,12 @@ cmState::CreateBuildsystemDirectorySnapshot(Snapshot originSnapshot,
pos->ExecutionListFile =
this->ExecutionListFiles.Extend(
originSnapshot.Position->ExecutionListFile);
+ pos->BuildSystemDirectory->DirectoryEnd = pos;
+ pos->Policies = originSnapshot.Position->Policies;
+ pos->PolicyRoot = originSnapshot.Position->Policies;
+ pos->PolicyScope = originSnapshot.Position->Policies;
+ assert(pos->Policies.IsValid());
+ assert(pos->PolicyRoot.IsValid());
return cmState::Snapshot(this, pos);
}
@@ -754,12 +787,13 @@ cmState::CreateFunctionCallSnapshot(cmState::Snapshot originSnapshot,
{
PositionType pos = this->SnapshotData.Extend(originSnapshot.Position,
*originSnapshot.Position);
- pos->CallStackParent = originSnapshot.Position;
pos->EntryPointLine = entryPointLine;
pos->EntryPointCommand = entryPointCommand;
pos->SnapshotType = FunctionCallType;
pos->ExecutionListFile = this->ExecutionListFiles.Extend(
originSnapshot.Position->ExecutionListFile, fileName);
+ pos->BuildSystemDirectory->DirectoryEnd = pos;
+ pos->PolicyScope = originSnapshot.Position->Policies;
return cmState::Snapshot(this, pos);
}
@@ -772,12 +806,13 @@ cmState::CreateMacroCallSnapshot(cmState::Snapshot originSnapshot,
{
PositionType pos = this->SnapshotData.Extend(originSnapshot.Position,
*originSnapshot.Position);
- pos->CallStackParent = originSnapshot.Position;
pos->EntryPointLine = entryPointLine;
pos->EntryPointCommand = entryPointCommand;
pos->SnapshotType = MacroCallType;
pos->ExecutionListFile = this->ExecutionListFiles.Extend(
originSnapshot.Position->ExecutionListFile, fileName);
+ pos->BuildSystemDirectory->DirectoryEnd = pos;
+ pos->PolicyScope = originSnapshot.Position->Policies;
return cmState::Snapshot(this, pos);
}
@@ -789,12 +824,13 @@ cmState::CreateCallStackSnapshot(cmState::Snapshot originSnapshot,
{
PositionType pos = this->SnapshotData.Extend(originSnapshot.Position,
*originSnapshot.Position);
- pos->CallStackParent = originSnapshot.Position;
pos->EntryPointLine = entryPointLine;
pos->EntryPointCommand = entryPointCommand;
pos->SnapshotType = CallStackType;
pos->ExecutionListFile = this->ExecutionListFiles.Extend(
originSnapshot.Position->ExecutionListFile, fileName);
+ pos->BuildSystemDirectory->DirectoryEnd = pos;
+ pos->PolicyScope = originSnapshot.Position->Policies;
return cmState::Snapshot(this, pos);
}
@@ -806,12 +842,24 @@ cmState::CreateInlineListFileSnapshot(cmState::Snapshot originSnapshot,
{
PositionType pos = this->SnapshotData.Extend(originSnapshot.Position,
*originSnapshot.Position);
- pos->CallStackParent = originSnapshot.Position;
pos->EntryPointLine = entryPointLine;
pos->EntryPointCommand = entryPointCommand;
pos->SnapshotType = InlineListFileType;
pos->ExecutionListFile = this->ExecutionListFiles.Extend(
originSnapshot.Position->ExecutionListFile, fileName);
+ pos->BuildSystemDirectory->DirectoryEnd = pos;
+ pos->PolicyScope = originSnapshot.Position->Policies;
+ return cmState::Snapshot(this, pos);
+}
+
+cmState::Snapshot
+cmState::CreatePolicyScopeSnapshot(cmState::Snapshot originSnapshot)
+{
+ PositionType pos = this->SnapshotData.Extend(originSnapshot.Position,
+ *originSnapshot.Position);
+ pos->SnapshotType = PolicyScopeType;
+ pos->BuildSystemDirectory->DirectoryEnd = pos;
+ pos->PolicyScope = originSnapshot.Position->Policies;
return cmState::Snapshot(this, pos);
}
@@ -826,12 +874,9 @@ cmState::Snapshot cmState::Pop(cmState::Snapshot originSnapshot)
prevPos->BuildSystemDirectory->CompileDefinitions.size();
prevPos->CompileOptionsPosition =
prevPos->BuildSystemDirectory->CompileOptions.size();
+ prevPos->BuildSystemDirectory->DirectoryEnd = prevPos;
- if (prevPos == this->SnapshotData.Root())
- {
- return Snapshot(this, prevPos);
- }
- return Snapshot(this, originSnapshot.Position->CallStackParent);
+ return Snapshot(this, prevPos);
}
cmState::Snapshot::Snapshot(cmState* state)
@@ -847,6 +892,11 @@ cmState::Snapshot::Snapshot(cmState* state, PositionType position)
}
+cmState::SnapshotType cmState::Snapshot::GetType() const
+{
+ return this->Position->SnapshotType;
+}
+
const char* cmState::Directory::GetCurrentSource() const
{
return this->DirectoryState->Location.c_str();
@@ -964,13 +1014,22 @@ cmState::Snapshot cmState::Snapshot::GetCallStackParent() const
assert(this->Position != this->State->SnapshotData.Root());
Snapshot snapshot;
- if (this->Position->SnapshotType == cmState::BuildsystemDirectoryType)
+ PositionType parentPos = this->Position;
+ while(parentPos->SnapshotType == cmState::PolicyScopeType)
+ {
+ ++parentPos;
+ }
+ if (parentPos->SnapshotType == cmState::BuildsystemDirectoryType)
{
return snapshot;
}
- PositionType parentPos = this->Position;
++parentPos;
+ while(parentPos->SnapshotType == cmState::PolicyScopeType)
+ {
+ ++parentPos;
+ }
+
if (parentPos == this->State->SnapshotData.Root())
{
return snapshot;
@@ -980,6 +1039,88 @@ cmState::Snapshot cmState::Snapshot::GetCallStackParent() const
return snapshot;
}
+void cmState::Snapshot::PushPolicy(cmPolicies::PolicyMap entry, bool weak)
+{
+ PositionType pos = this->Position;
+ pos->Policies =
+ this->State->PolicyStack.Extend(pos->Policies,
+ PolicyStackEntry(entry, weak));
+}
+
+bool cmState::Snapshot::PopPolicy()
+{
+ PositionType pos = this->Position;
+ if (pos->Policies == pos->PolicyScope)
+ {
+ return false;
+ }
+ ++pos->Policies;
+ return true;
+}
+
+bool cmState::Snapshot::CanPopPolicyScope()
+{
+ return this->Position->Policies == this->Position->PolicyScope;
+}
+
+void cmState::Snapshot::SetPolicy(cmPolicies::PolicyID id,
+ cmPolicies::PolicyStatus status)
+{
+ // Update the policy stack from the top to the top-most strong entry.
+ bool previous_was_weak = true;
+ for(cmLinkedTree<PolicyStackEntry>::iterator psi = this->Position->Policies;
+ previous_was_weak && psi != this->Position->PolicyRoot; ++psi)
+ {
+ psi->Set(id, status);
+ previous_was_weak = psi->Weak;
+ }
+}
+
+cmPolicies::PolicyStatus
+cmState::Snapshot::GetPolicy(cmPolicies::PolicyID id) const
+{
+ cmPolicies::PolicyStatus status = cmPolicies::GetPolicyStatus(id);
+
+ if(status == cmPolicies::REQUIRED_ALWAYS ||
+ status == cmPolicies::REQUIRED_IF_USED)
+ {
+ return status;
+ }
+
+ cmLinkedTree<BuildsystemDirectoryStateType>::iterator dir =
+ this->Position->BuildSystemDirectory;
+
+ while (true)
+ {
+ assert(dir.IsValid());
+ cmLinkedTree<PolicyStackEntry>::iterator leaf =
+ dir->DirectoryEnd->Policies;
+ cmLinkedTree<PolicyStackEntry>::iterator root =
+ dir->DirectoryEnd->PolicyRoot;
+ for( ; leaf != root; ++leaf)
+ {
+ if(leaf->IsDefined(id))
+ {
+ status = leaf->Get(id);
+ return status;
+ }
+ }
+ cmState::PositionType e = dir->DirectoryEnd;
+ cmState::PositionType p = e->DirectoryParent;
+ if (p == this->State->SnapshotData.Root())
+ {
+ break;
+ }
+ dir = p->BuildSystemDirectory;
+ }
+ return status;
+}
+
+bool cmState::Snapshot::HasDefinedPolicyCMP0011()
+{
+ return !this->Position->Policies->IsEmpty();
+}
+
static const std::string cmPropertySentinal = std::string();
template<typename T, typename U, typename V>
diff --git a/Source/cmState.h b/Source/cmState.h
index 0d5300f..07aa2a5 100644
--- a/Source/cmState.h
+++ b/Source/cmState.h
@@ -17,6 +17,7 @@
#include "cmPropertyMap.h"
#include "cmLinkedTree.h"
#include "cmAlgorithms.h"
+#include "cmPolicies.h"
class cmake;
class cmCommand;
@@ -24,6 +25,7 @@ class cmCommand;
class cmState
{
struct SnapshotDataType;
+ struct PolicyStackEntry;
struct BuildsystemDirectoryStateType;
typedef cmLinkedTree<SnapshotDataType>::iterator PositionType;
friend class Snapshot;
@@ -37,7 +39,8 @@ public:
FunctionCallType,
MacroCallType,
CallStackType,
- InlineListFileType
+ InlineListFileType,
+ PolicyScopeType
};
class Directory;
@@ -56,9 +59,17 @@ public:
bool IsValid() const;
Snapshot GetBuildsystemDirectoryParent() const;
Snapshot GetCallStackParent() const;
+ SnapshotType GetType() const;
void InitializeFromParent();
+ void SetPolicy(cmPolicies::PolicyID id, cmPolicies::PolicyStatus status);
+ cmPolicies::PolicyStatus GetPolicy(cmPolicies::PolicyID id) const;
+ bool HasDefinedPolicyCMP0011();
+ void PushPolicy(cmPolicies::PolicyMap entry, bool weak);
+ bool PopPolicy();
+ bool CanPopPolicyScope();
+
cmState* GetState() const;
Directory GetDirectory() const;
@@ -147,6 +158,7 @@ public:
const std::string& entryPointCommand,
long entryPointLine,
std::string const& fileName);
+ Snapshot CreatePolicyScopeSnapshot(Snapshot originSnapshot);
Snapshot Pop(Snapshot originSnapshot);
enum CacheEntryType{ BOOL=0, PATH, FILEPATH, STRING, INTERNAL,STATIC,
@@ -254,6 +266,7 @@ private:
cmLinkedTree<std::string> ExecutionListFiles;
+ cmLinkedTree<PolicyStackEntry> PolicyStack;
cmLinkedTree<SnapshotDataType> SnapshotData;
std::vector<std::string> SourceDirectoryComponents;
diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx
index 2543e68..a117238 100644
--- a/Source/cmSystemTools.cxx
+++ b/Source/cmSystemTools.cxx
@@ -950,8 +950,9 @@ bool cmSystemTools::RenameFile(const char* oldname, const char* newname)
Try multiple times since we may be racing against another process
creating/opening the destination file just before our MoveFileEx. */
WindowsFileRetry retry = cmSystemTools::GetWindowsFileRetry();
- while(!MoveFileExW(cmsys::Encoding::ToWide(oldname).c_str(),
- cmsys::Encoding::ToWide(newname).c_str(),
+ while(!MoveFileExW(
+ SystemTools::ConvertToWindowsExtendedPath(oldname).c_str(),
+ SystemTools::ConvertToWindowsExtendedPath(newname).c_str(),
MOVEFILE_REPLACE_EXISTING) && --retry.Count)
{
DWORD last_error = GetLastError();
@@ -962,12 +963,14 @@ bool cmSystemTools::RenameFile(const char* oldname, const char* newname)
return false;
}
DWORD attrs =
- GetFileAttributesW(cmsys::Encoding::ToWide(newname).c_str());
+ GetFileAttributesW(
+ SystemTools::ConvertToWindowsExtendedPath(newname).c_str());
if((attrs != INVALID_FILE_ATTRIBUTES) &&
(attrs & FILE_ATTRIBUTE_READONLY))
{
// Remove the read-only attribute from the destination file.
- SetFileAttributesW(cmsys::Encoding::ToWide(newname).c_str(),
+ SetFileAttributesW(
+ SystemTools::ConvertToWindowsExtendedPath(newname).c_str(),
attrs & ~FILE_ATTRIBUTE_READONLY);
}
else
@@ -1956,11 +1959,11 @@ bool cmSystemTools::CopyFileTime(const char* fromFile, const char* toFile)
{
#if defined(_WIN32) && !defined(__CYGWIN__)
cmSystemToolsWindowsHandle hFrom =
- CreateFileW(cmsys::Encoding::ToWide(fromFile).c_str(),
+ CreateFileW(SystemTools::ConvertToWindowsExtendedPath(fromFile).c_str(),
GENERIC_READ, FILE_SHARE_READ, 0,
OPEN_EXISTING, 0, 0);
cmSystemToolsWindowsHandle hTo =
- CreateFileW(cmsys::Encoding::ToWide(toFile).c_str(),
+ CreateFileW(SystemTools::ConvertToWindowsExtendedPath(toFile).c_str(),
GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
if(!hFrom || !hTo)
{
@@ -2012,7 +2015,7 @@ bool cmSystemTools::FileTimeGet(const char* fname, cmSystemToolsFileTime* t)
{
#if defined(_WIN32) && !defined(__CYGWIN__)
cmSystemToolsWindowsHandle h =
- CreateFileW(cmsys::Encoding::ToWide(fname).c_str(),
+ CreateFileW(SystemTools::ConvertToWindowsExtendedPath(fname).c_str(),
GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
if(!h)
{
@@ -2039,7 +2042,7 @@ bool cmSystemTools::FileTimeSet(const char* fname, cmSystemToolsFileTime* t)
{
#if defined(_WIN32) && !defined(__CYGWIN__)
cmSystemToolsWindowsHandle h =
- CreateFileW(cmsys::Encoding::ToWide(fname).c_str(),
+ CreateFileW(SystemTools::ConvertToWindowsExtendedPath(fname).c_str(),
GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
if(!h)
{
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index cf33791..49b3239 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -66,27 +66,8 @@ struct cmTarget::OutputInfo
std::string OutDir;
std::string ImpDir;
std::string PdbDir;
-};
-
-//----------------------------------------------------------------------------
-struct cmTarget::ImportInfo
-{
- ImportInfo(): NoSOName(false), Multiplicity(0) {}
- bool NoSOName;
- int Multiplicity;
- std::string Location;
- std::string SOName;
- std::string ImportLibrary;
- std::string Languages;
- std::string Libraries;
- std::string LibrariesProp;
- std::string SharedDeps;
-};
-
-//----------------------------------------------------------------------------
-struct cmTarget::CompileInfo
-{
- std::string CompilePdbDir;
+ bool empty() const
+ { return OutDir.empty() && ImpDir.empty() && PdbDir.empty(); }
};
//----------------------------------------------------------------------------
@@ -147,9 +128,6 @@ public:
typedef std::map<std::string, cmTarget::ImportInfo> ImportInfoMapType;
ImportInfoMapType ImportInfoMap;
- typedef std::map<std::string, cmTarget::CompileInfo> CompileInfoMapType;
- CompileInfoMapType CompileInfoMap;
-
// Cache link implementation computation from each configuration.
struct OptionalLinkImplementation: public cmTarget::LinkImplementation
{
@@ -175,23 +153,6 @@ public:
HeadToLinkImplementationMap> LinkImplMapType;
LinkImplMapType LinkImplMap;
- typedef std::map<std::string, cmTarget::LinkClosure> LinkClosureMapType;
- LinkClosureMapType LinkClosureMap;
-
- struct LinkImplClosure: public std::vector<cmTarget const*>
- {
- LinkImplClosure(): Done(false) {}
- bool Done;
- };
- std::map<std::string, LinkImplClosure> LinkImplClosureMap;
-
- struct CompatibleInterfaces: public cmTarget::CompatibleInterfaces
- {
- CompatibleInterfaces(): Done(false) {}
- bool Done;
- };
- std::map<std::string, CompatibleInterfaces> CompatibleInterfacesMap;
-
typedef std::map<std::string, std::vector<cmSourceFile*> >
SourceFilesMapType;
SourceFilesMapType SourceFilesMap;
@@ -209,10 +170,18 @@ public:
const cmsys::auto_ptr<cmCompiledGeneratorExpression> ge;
cmLinkImplItem const& LinkImplItem;
};
- std::vector<TargetPropertyEntry*> IncludeDirectoriesEntries;
- std::vector<TargetPropertyEntry*> CompileOptionsEntries;
- std::vector<TargetPropertyEntry*> CompileFeaturesEntries;
- std::vector<TargetPropertyEntry*> CompileDefinitionsEntries;
+ std::vector<std::string> IncludeDirectoriesEntries;
+ std::vector<cmListFileBacktrace> IncludeDirectoriesBacktraces;
+ std::vector<TargetPropertyEntry*> IncludeDirectoriesItems;
+ std::vector<std::string> CompileOptionsEntries;
+ std::vector<cmListFileBacktrace> CompileOptionsBacktraces;
+ std::vector<TargetPropertyEntry*> CompileOptionsItems;
+ std::vector<std::string> CompileFeaturesEntries;
+ std::vector<cmListFileBacktrace> CompileFeaturesBacktraces;
+ std::vector<TargetPropertyEntry*> CompileFeaturesItems;
+ std::vector<std::string> CompileDefinitionsEntries;
+ std::vector<cmListFileBacktrace> CompileDefinitionsBacktraces;
+ std::vector<TargetPropertyEntry*> CompileDefinitionsItems;
std::vector<TargetPropertyEntry*> SourceEntries;
std::vector<cmValueWithOrigin> LinkImplementationPropertyEntries;
@@ -224,14 +193,6 @@ public:
cmLinkImplItem cmTargetInternals::TargetPropertyEntry::NoLinkImplItem;
//----------------------------------------------------------------------------
-static void deleteAndClear(
- std::vector<cmTargetInternals::TargetPropertyEntry*> &entries)
-{
- cmDeleteAll(entries);
- entries.clear();
-}
-
-//----------------------------------------------------------------------------
cmTargetInternals::~cmTargetInternals()
{
}
@@ -347,6 +308,8 @@ void cmTarget::SetMakefile(cmMakefile* mf)
this->SetPropertyDefault("CXX_STANDARD", 0);
this->SetPropertyDefault("CXX_STANDARD_REQUIRED", 0);
this->SetPropertyDefault("CXX_EXTENSIONS", 0);
+ this->SetPropertyDefault("LINK_SEARCH_START_STATIC", 0);
+ this->SetPropertyDefault("LINK_SEARCH_END_STATIC", 0);
}
// Collect the set of configuration types.
@@ -407,13 +370,13 @@ void cmTarget::SetMakefile(cmMakefile* mf)
const cmBacktraceRange parentIncludesBts =
this->Makefile->GetIncludeDirectoriesBacktraces();
- cmBacktraceRange::const_iterator btIt = parentIncludesBts.begin();
- for (cmStringRange::const_iterator it
- = parentIncludes.begin();
- it != parentIncludes.end(); ++it, ++btIt)
- {
- this->InsertInclude(*it, *btIt);
- }
+ this->Internal->IncludeDirectoriesEntries.insert(
+ this->Internal->IncludeDirectoriesEntries.end(),
+ parentIncludes.begin(), parentIncludes.end());
+ this->Internal->IncludeDirectoriesBacktraces.insert(
+ this->Internal->IncludeDirectoriesBacktraces.end(),
+ parentIncludesBts.begin(), parentIncludesBts.end());
+
const std::set<std::string> parentSystemIncludes =
this->Makefile->GetSystemIncludeDirectories();
@@ -425,13 +388,12 @@ void cmTarget::SetMakefile(cmMakefile* mf)
const cmBacktraceRange parentOptionsBts =
this->Makefile->GetCompileOptionsBacktraces();
- btIt = parentOptionsBts.begin();
- for (cmStringRange::const_iterator it
- = parentOptions.begin();
- it != parentOptions.end(); ++it, ++btIt)
- {
- this->InsertCompileOption(*it, *btIt);
- }
+ this->Internal->CompileOptionsEntries.insert(
+ this->Internal->CompileOptionsEntries.end(),
+ parentOptions.begin(), parentOptions.end());
+ this->Internal->CompileOptionsBacktraces.insert(
+ this->Internal->CompileOptionsBacktraces.end(),
+ parentOptionsBts.begin(), parentOptionsBts.end());
}
if (this->GetType() != INTERFACE_LIBRARY && this->GetType() != UTILITY)
@@ -479,6 +441,44 @@ void cmTarget::SetMakefile(cmMakefile* mf)
}
}
+void CreatePropertyGeneratorExpressions(
+ std::vector<std::string> const& entries,
+ std::vector<cmListFileBacktrace> const& backtraces,
+ std::vector<cmTargetInternals::TargetPropertyEntry*>& items)
+{
+ std::vector<cmListFileBacktrace>::const_iterator btIt = backtraces.begin();
+ for (std::vector<std::string>::const_iterator it = entries.begin();
+ it != entries.end(); ++it, ++btIt)
+ {
+ cmGeneratorExpression ge(*btIt);
+ cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(*it);
+ items.push_back(new cmTargetInternals::TargetPropertyEntry(cge));
+ }
+}
+
+void cmTarget::Compute()
+{
+ CreatePropertyGeneratorExpressions(
+ this->Internal->IncludeDirectoriesEntries,
+ this->Internal->IncludeDirectoriesBacktraces,
+ this->Internal->IncludeDirectoriesItems);
+
+ CreatePropertyGeneratorExpressions(
+ this->Internal->CompileOptionsEntries,
+ this->Internal->CompileOptionsBacktraces,
+ this->Internal->CompileOptionsItems);
+
+ CreatePropertyGeneratorExpressions(
+ this->Internal->CompileFeaturesEntries,
+ this->Internal->CompileFeaturesBacktraces,
+ this->Internal->CompileFeaturesItems);
+
+ CreatePropertyGeneratorExpressions(
+ this->Internal->CompileDefinitionsEntries,
+ this->Internal->CompileDefinitionsBacktraces,
+ this->Internal->CompileDefinitionsItems);
+}
+
//----------------------------------------------------------------------------
void cmTarget::AddUtility(const std::string& u, cmMakefile *makefile)
{
@@ -540,10 +540,7 @@ void cmTarget::ClearLinkMaps()
this->Internal->LinkImplMap.clear();
this->Internal->LinkInterfaceMap.clear();
this->Internal->LinkInterfaceUsageRequirementsOnlyMap.clear();
- this->Internal->LinkClosureMap.clear();
this->Internal->SourceFilesMap.clear();
- cmDeleteAll(this->LinkInformation);
- this->LinkInformation.clear();
}
//----------------------------------------------------------------------------
@@ -625,13 +622,6 @@ bool cmTarget::IsXCTestOnApple() const
}
//----------------------------------------------------------------------------
-bool cmTarget::IsBundleOnApple() const
-{
- return this->IsFrameworkOnApple() || this->IsAppBundleOnApple() ||
- this->IsCFBundleOnApple();
-}
-
-//----------------------------------------------------------------------------
static bool processSources(cmTarget const* tgt,
const std::vector<cmTargetInternals::TargetPropertyEntry*> &entries,
std::vector<std::string> &srcs,
@@ -816,7 +806,7 @@ void cmTarget::GetSourceFiles(std::vector<std::string> &files,
this->LinkImplementationLanguageIsContextDependent = false;
}
- deleteAndClear(linkInterfaceSourcesEntries);
+ cmDeleteAll(linkInterfaceSourcesEntries);
}
//----------------------------------------------------------------------------
@@ -1364,13 +1354,6 @@ cmTarget::AddSystemIncludeDirectories(const std::set<std::string> &incs)
this->SystemIncludeDirectories.insert(incs.begin(), incs.end());
}
-//----------------------------------------------------------------------------
-void
-cmTarget::AddSystemIncludeDirectories(const std::vector<std::string> &incs)
-{
- this->SystemIncludeDirectories.insert(incs.begin(), incs.end());
-}
-
#if defined(_WIN32) && !defined(__CYGWIN__)
//----------------------------------------------------------------------------
void
@@ -1717,39 +1700,35 @@ void cmTarget::SetProperty(const std::string& prop, const char* value)
}
else if(prop == "INCLUDE_DIRECTORIES")
{
+ this->Internal->IncludeDirectoriesEntries.clear();
+ this->Internal->IncludeDirectoriesBacktraces.clear();
+ this->Internal->IncludeDirectoriesEntries.push_back(value);
cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
- cmGeneratorExpression ge(lfbt);
- deleteAndClear(this->Internal->IncludeDirectoriesEntries);
- cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(value);
- this->Internal->IncludeDirectoriesEntries.push_back(
- new cmTargetInternals::TargetPropertyEntry(cge));
+ this->Internal->IncludeDirectoriesBacktraces.push_back(lfbt);
}
else if(prop == "COMPILE_OPTIONS")
{
+ this->Internal->CompileOptionsEntries.clear();
+ this->Internal->CompileOptionsBacktraces.clear();
+ this->Internal->CompileOptionsEntries.push_back(value);
cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
- cmGeneratorExpression ge(lfbt);
- deleteAndClear(this->Internal->CompileOptionsEntries);
- cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(value);
- this->Internal->CompileOptionsEntries.push_back(
- new cmTargetInternals::TargetPropertyEntry(cge));
+ this->Internal->CompileOptionsBacktraces.push_back(lfbt);
}
else if(prop == "COMPILE_FEATURES")
{
+ this->Internal->CompileFeaturesEntries.clear();
+ this->Internal->CompileFeaturesBacktraces.clear();
+ this->Internal->CompileFeaturesEntries.push_back(value);
cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
- cmGeneratorExpression ge(lfbt);
- deleteAndClear(this->Internal->CompileFeaturesEntries);
- cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(value);
- this->Internal->CompileFeaturesEntries.push_back(
- new cmTargetInternals::TargetPropertyEntry(cge));
+ this->Internal->CompileFeaturesBacktraces.push_back(lfbt);
}
else if(prop == "COMPILE_DEFINITIONS")
{
+ this->Internal->CompileDefinitionsEntries.clear();
+ this->Internal->CompileDefinitionsBacktraces.clear();
+ this->Internal->CompileDefinitionsEntries.push_back(value);
cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
- cmGeneratorExpression ge(lfbt);
- deleteAndClear(this->Internal->CompileDefinitionsEntries);
- cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(value);
- this->Internal->CompileDefinitionsEntries.push_back(
- new cmTargetInternals::TargetPropertyEntry(cge));
+ this->Internal->CompileDefinitionsBacktraces.push_back(lfbt);
}
else if(prop == "EXPORT_NAME" && this->IsImported())
{
@@ -1815,31 +1794,27 @@ void cmTarget::AppendProperty(const std::string& prop, const char* value,
}
else if(prop == "INCLUDE_DIRECTORIES")
{
+ this->Internal->IncludeDirectoriesEntries.push_back(value);
cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
- cmGeneratorExpression ge(lfbt);
- this->Internal->IncludeDirectoriesEntries.push_back(
- new cmTargetInternals::TargetPropertyEntry(ge.Parse(value)));
+ this->Internal->IncludeDirectoriesBacktraces.push_back(lfbt);
}
else if(prop == "COMPILE_OPTIONS")
{
+ this->Internal->CompileOptionsEntries.push_back(value);
cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
- cmGeneratorExpression ge(lfbt);
- this->Internal->CompileOptionsEntries.push_back(
- new cmTargetInternals::TargetPropertyEntry(ge.Parse(value)));
+ this->Internal->CompileOptionsBacktraces.push_back(lfbt);
}
else if(prop == "COMPILE_FEATURES")
{
+ this->Internal->CompileFeaturesEntries.push_back(value);
cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
- cmGeneratorExpression ge(lfbt);
- this->Internal->CompileFeaturesEntries.push_back(
- new cmTargetInternals::TargetPropertyEntry(ge.Parse(value)));
+ this->Internal->CompileFeaturesBacktraces.push_back(lfbt);
}
else if(prop == "COMPILE_DEFINITIONS")
{
+ this->Internal->CompileDefinitionsEntries.push_back(value);
cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
- cmGeneratorExpression ge(lfbt);
- this->Internal->CompileDefinitionsEntries.push_back(
- new cmTargetInternals::TargetPropertyEntry(ge.Parse(value)));
+ this->Internal->CompileDefinitionsBacktraces.push_back(lfbt);
}
else if(prop == "EXPORT_NAME" && this->IsImported())
{
@@ -1938,14 +1913,16 @@ void cmTarget::InsertInclude(std::string const& entry,
cmListFileBacktrace const& bt,
bool before)
{
- cmGeneratorExpression ge(bt);
+ std::vector<std::string>::iterator position =
+ before ? this->Internal->IncludeDirectoriesEntries.begin()
+ : this->Internal->IncludeDirectoriesEntries.end();
- std::vector<cmTargetInternals::TargetPropertyEntry*>::iterator position
- = before ? this->Internal->IncludeDirectoriesEntries.begin()
- : this->Internal->IncludeDirectoriesEntries.end();
+ std::vector<cmListFileBacktrace>::iterator btPosition =
+ before ? this->Internal->IncludeDirectoriesBacktraces.begin()
+ : this->Internal->IncludeDirectoriesBacktraces.end();
- this->Internal->IncludeDirectoriesEntries.insert(position,
- new cmTargetInternals::TargetPropertyEntry(ge.Parse(entry)));
+ this->Internal->IncludeDirectoriesEntries.insert(position, entry);
+ this->Internal->IncludeDirectoriesBacktraces.insert(btPosition, bt);
}
//----------------------------------------------------------------------------
@@ -1953,24 +1930,24 @@ void cmTarget::InsertCompileOption(std::string const& entry,
cmListFileBacktrace const& bt,
bool before)
{
- cmGeneratorExpression ge(bt);
+ std::vector<std::string>::iterator position =
+ before ? this->Internal->CompileOptionsEntries.begin()
+ : this->Internal->CompileOptionsEntries.end();
- std::vector<cmTargetInternals::TargetPropertyEntry*>::iterator position
- = before ? this->Internal->CompileOptionsEntries.begin()
- : this->Internal->CompileOptionsEntries.end();
+ std::vector<cmListFileBacktrace>::iterator btPosition =
+ before ? this->Internal->CompileOptionsBacktraces.begin()
+ : this->Internal->CompileOptionsBacktraces.end();
- this->Internal->CompileOptionsEntries.insert(position,
- new cmTargetInternals::TargetPropertyEntry(ge.Parse(entry)));
+ this->Internal->CompileOptionsEntries.insert(position, entry);
+ this->Internal->CompileOptionsBacktraces.insert(btPosition, bt);
}
//----------------------------------------------------------------------------
void cmTarget::InsertCompileDefinition(std::string const& entry,
cmListFileBacktrace const& bt)
{
- cmGeneratorExpression ge(bt);
-
- this->Internal->CompileDefinitionsEntries.push_back(
- new cmTargetInternals::TargetPropertyEntry(ge.Parse(entry)));
+ this->Internal->CompileDefinitionsEntries.push_back(entry);
+ this->Internal->CompileDefinitionsBacktraces.push_back(bt);
}
//----------------------------------------------------------------------------
@@ -2134,7 +2111,7 @@ cmTarget::GetIncludeDirectories(const std::string& config,
}
processIncludeDirectories(this,
- this->Internal->IncludeDirectoriesEntries,
+ this->Internal->IncludeDirectoriesItems,
includes,
uniqueIncludes,
&dagChecker,
@@ -2150,7 +2127,8 @@ cmTarget::GetIncludeDirectories(const std::string& config,
if(this->Makefile->IsOn("APPLE"))
{
- LinkImplementation const* impl = this->GetLinkImplementation(config);
+ cmLinkImplementationLibraries const* impl =
+ this->GetLinkImplementationLibraries(config);
for(std::vector<cmLinkImplItem>::const_iterator
it = impl->Libraries.begin();
it != impl->Libraries.end(); ++it)
@@ -2183,7 +2161,7 @@ cmTarget::GetIncludeDirectories(const std::string& config,
debugIncludes,
language);
- deleteAndClear(linkInterfaceIncludeDirectoriesEntries);
+ cmDeleteAll(linkInterfaceIncludeDirectoriesEntries);
return includes;
}
@@ -2251,31 +2229,6 @@ static void processCompileOptions(cmTarget const* tgt,
}
//----------------------------------------------------------------------------
-void cmTarget::GetAutoUicOptions(std::vector<std::string> &result,
- const std::string& config) const
-{
- const char *prop
- = this->GetLinkInterfaceDependentStringProperty("AUTOUIC_OPTIONS",
- config);
- if (!prop)
- {
- return;
- }
- cmGeneratorExpression ge;
-
- cmGeneratorExpressionDAGChecker dagChecker(
- this->GetName(),
- "AUTOUIC_OPTIONS", 0, 0);
- cmSystemTools::ExpandListArgument(ge.Parse(prop)
- ->Evaluate(this->Makefile,
- config,
- false,
- this,
- &dagChecker),
- result);
-}
-
-//----------------------------------------------------------------------------
void cmTarget::GetCompileOptions(std::vector<std::string> &result,
const std::string& config,
const std::string& language) const
@@ -2305,7 +2258,7 @@ void cmTarget::GetCompileOptions(std::vector<std::string> &result,
}
processCompileOptions(this,
- this->Internal->CompileOptionsEntries,
+ this->Internal->CompileOptionsItems,
result,
uniqueOptions,
&dagChecker,
@@ -2329,7 +2282,7 @@ void cmTarget::GetCompileOptions(std::vector<std::string> &result,
debugOptions,
language);
- deleteAndClear(linkInterfaceCompileOptionsEntries);
+ cmDeleteAll(linkInterfaceCompileOptionsEntries);
}
//----------------------------------------------------------------------------
@@ -2376,7 +2329,7 @@ void cmTarget::GetCompileDefinitions(std::vector<std::string> &list,
}
processCompileDefinitions(this,
- this->Internal->CompileDefinitionsEntries,
+ this->Internal->CompileDefinitionsItems,
list,
uniqueOptions,
&dagChecker,
@@ -2431,7 +2384,7 @@ void cmTarget::GetCompileDefinitions(std::vector<std::string> &list,
debugDefines,
language);
- deleteAndClear(linkInterfaceCompileDefinitionsEntries);
+ cmDeleteAll(linkInterfaceCompileDefinitionsEntries);
}
//----------------------------------------------------------------------------
@@ -2477,7 +2430,7 @@ void cmTarget::GetCompileFeatures(std::vector<std::string> &result,
}
processCompileFeatures(this,
- this->Internal->CompileFeaturesEntries,
+ this->Internal->CompileFeaturesItems,
result,
uniqueFeatures,
&dagChecker,
@@ -2498,7 +2451,7 @@ void cmTarget::GetCompileFeatures(std::vector<std::string> &result,
config,
debugFeatures);
- deleteAndClear(linkInterfaceCompileFeaturesEntries);
+ cmDeleteAll(linkInterfaceCompileFeaturesEntries);
}
//----------------------------------------------------------------------------
@@ -2653,59 +2606,36 @@ cmTarget::OutputInfo const* cmTarget::GetOutputInfo(
config_upper = cmSystemTools::UpperCase(config);
}
typedef cmTargetInternals::OutputInfoMapType OutputInfoMapType;
- OutputInfoMapType::const_iterator i =
+ OutputInfoMapType::iterator i =
this->Internal->OutputInfoMap.find(config_upper);
if(i == this->Internal->OutputInfoMap.end())
{
+ // Add empty info in map to detect potential recursion.
OutputInfo info;
+ OutputInfoMapType::value_type entry(config_upper, info);
+ i = this->Internal->OutputInfoMap.insert(entry).first;
+
+ // Compute output directories.
this->ComputeOutputDir(config, false, info.OutDir);
this->ComputeOutputDir(config, true, info.ImpDir);
if(!this->ComputePDBOutputDir("PDB", config, info.PdbDir))
{
info.PdbDir = info.OutDir;
}
- OutputInfoMapType::value_type entry(config_upper, info);
- i = this->Internal->OutputInfoMap.insert(entry).first;
- }
- return &i->second;
-}
-//----------------------------------------------------------------------------
-cmTarget::CompileInfo const* cmTarget::GetCompileInfo(
- const std::string& config) const
-{
- // There is no compile information for imported targets.
- if(this->IsImported())
- {
- return 0;
+ // Now update the previously-prepared map entry.
+ i->second = info;
}
-
- if(this->GetType() > cmTarget::OBJECT_LIBRARY)
+ else if(i->second.empty())
{
- std::string msg = "cmTarget::GetCompileInfo called for ";
- msg += this->GetName();
- msg += " which has type ";
- msg += cmTarget::GetTargetTypeName(this->GetType());
- this->GetMakefile()->IssueMessage(cmake::INTERNAL_ERROR, msg);
+ // An empty map entry indicates we have been called recursively
+ // from the above block.
+ this->Makefile->GetCMakeInstance()->IssueMessage(
+ cmake::FATAL_ERROR,
+ "Target '" + this->GetName() + "' OUTPUT_DIRECTORY depends on itself.",
+ this->GetBacktrace());
return 0;
}
-
- // Lookup/compute/cache the compile information for this configuration.
- std::string config_upper;
- if(!config.empty())
- {
- config_upper = cmSystemTools::UpperCase(config);
- }
- typedef cmTargetInternals::CompileInfoMapType CompileInfoMapType;
- CompileInfoMapType::const_iterator i =
- this->Internal->CompileInfoMap.find(config_upper);
- if(i == this->Internal->CompileInfoMap.end())
- {
- CompileInfo info;
- this->ComputePDBOutputDir("COMPILE_PDB", config, info.CompilePdbDir);
- CompileInfoMapType::value_type entry(config_upper, info);
- i = this->Internal->CompileInfoMap.insert(entry).first;
- }
return &i->second;
}
@@ -2740,16 +2670,6 @@ std::string cmTarget::GetPDBDirectory(const std::string& config) const
}
//----------------------------------------------------------------------------
-std::string cmTarget::GetCompilePDBDirectory(const std::string& config) const
-{
- if(CompileInfo const* info = this->GetCompileInfo(config))
- {
- return info->CompilePdbDir;
- }
- return "";
-}
-
-//----------------------------------------------------------------------------
const char* cmTarget::ImportedGetLocation(const std::string& config) const
{
static std::string location;
@@ -2833,22 +2753,6 @@ bool cmTarget::HandleLocationPropertyPolicy(cmMakefile* context) const
}
//----------------------------------------------------------------------------
-static void MakePropertyList(std::string& output,
- std::vector<cmTargetInternals::TargetPropertyEntry*> const& values)
-{
- output = "";
- std::string sep;
- for (std::vector<cmTargetInternals::TargetPropertyEntry*>::const_iterator
- it = values.begin(), end = values.end();
- it != end; ++it)
- {
- output += sep;
- output += (*it)->ge->GetInput();
- sep = ";";
- }
-}
-
-//----------------------------------------------------------------------------
const char *cmTarget::GetProperty(const std::string& prop) const
{
return this->GetProperty(prop, this->Makefile);
@@ -3023,7 +2927,7 @@ const char *cmTarget::GetProperty(const std::string& prop,
}
static std::string output;
- MakePropertyList(output, this->Internal->IncludeDirectoriesEntries);
+ output = cmJoin(this->Internal->IncludeDirectoriesEntries, ";");
return output.c_str();
}
else if(prop == propCOMPILE_FEATURES)
@@ -3034,7 +2938,7 @@ const char *cmTarget::GetProperty(const std::string& prop,
}
static std::string output;
- MakePropertyList(output, this->Internal->CompileFeaturesEntries);
+ output = cmJoin(this->Internal->CompileFeaturesEntries, ";");
return output.c_str();
}
else if(prop == propCOMPILE_OPTIONS)
@@ -3045,7 +2949,7 @@ const char *cmTarget::GetProperty(const std::string& prop,
}
static std::string output;
- MakePropertyList(output, this->Internal->CompileOptionsEntries);
+ output = cmJoin(this->Internal->CompileOptionsEntries, ";");
return output.c_str();
}
else if(prop == propCOMPILE_DEFINITIONS)
@@ -3056,7 +2960,7 @@ const char *cmTarget::GetProperty(const std::string& prop,
}
static std::string output;
- MakePropertyList(output, this->Internal->CompileDefinitionsEntries);
+ output = cmJoin(this->Internal->CompileDefinitionsEntries, ";");
return output.c_str();
}
else if (prop == propIMPORTED)
@@ -3192,229 +3096,6 @@ bool cmTarget::GetPropertyAsBool(const std::string& prop) const
}
//----------------------------------------------------------------------------
-class cmTargetCollectLinkLanguages
-{
-public:
- cmTargetCollectLinkLanguages(cmTarget const* target,
- const std::string& config,
- UNORDERED_SET<std::string>& languages,
- cmTarget const* head):
- Config(config), Languages(languages), HeadTarget(head),
- Makefile(target->GetMakefile()), Target(target)
- { this->Visited.insert(target); }
-
- void Visit(cmLinkItem const& item)
- {
- if(!item.Target)
- {
- if(item.find("::") != std::string::npos)
- {
- bool noMessage = false;
- cmake::MessageType messageType = cmake::FATAL_ERROR;
- std::ostringstream e;
- switch(this->Makefile->GetPolicyStatus(cmPolicies::CMP0028))
- {
- case cmPolicies::WARN:
- {
- e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0028) << "\n";
- messageType = cmake::AUTHOR_WARNING;
- }
- break;
- case cmPolicies::OLD:
- noMessage = true;
- case cmPolicies::REQUIRED_IF_USED:
- case cmPolicies::REQUIRED_ALWAYS:
- case cmPolicies::NEW:
- // Issue the fatal message.
- break;
- }
-
- if(!noMessage)
- {
- e << "Target \"" << this->Target->GetName()
- << "\" links to target \"" << item
- << "\" but the target was not found. Perhaps a find_package() "
- "call is missing for an IMPORTED target, or an ALIAS target is "
- "missing?";
- this->Makefile->GetCMakeInstance()->IssueMessage(messageType,
- e.str(),
- this->Target->GetBacktrace());
- }
- }
- return;
- }
- if(!this->Visited.insert(item.Target).second)
- {
- return;
- }
-
- cmTarget::LinkInterface const* iface =
- item.Target->GetLinkInterface(this->Config, this->HeadTarget);
- if(!iface) { return; }
-
- for(std::vector<std::string>::const_iterator
- li = iface->Languages.begin(); li != iface->Languages.end(); ++li)
- {
- this->Languages.insert(*li);
- }
-
- for(std::vector<cmLinkItem>::const_iterator
- li = iface->Libraries.begin(); li != iface->Libraries.end(); ++li)
- {
- this->Visit(*li);
- }
- }
-private:
- std::string Config;
- UNORDERED_SET<std::string>& Languages;
- cmTarget const* HeadTarget;
- cmMakefile* Makefile;
- const cmTarget* Target;
- std::set<cmTarget const*> Visited;
-};
-
-//----------------------------------------------------------------------------
-std::string cmTarget::GetLinkerLanguage(const std::string& config) const
-{
- return this->GetLinkClosure(config)->LinkerLanguage;
-}
-
-//----------------------------------------------------------------------------
-cmTarget::LinkClosure const*
-cmTarget::GetLinkClosure(const std::string& config) const
-{
- std::string key(cmSystemTools::UpperCase(config));
- cmTargetInternals::LinkClosureMapType::iterator
- i = this->Internal->LinkClosureMap.find(key);
- if(i == this->Internal->LinkClosureMap.end())
- {
- LinkClosure lc;
- this->ComputeLinkClosure(config, lc);
- cmTargetInternals::LinkClosureMapType::value_type entry(key, lc);
- i = this->Internal->LinkClosureMap.insert(entry).first;
- }
- return &i->second;
-}
-
-//----------------------------------------------------------------------------
-class cmTargetSelectLinker
-{
- int Preference;
- cmTarget const* Target;
- cmMakefile* Makefile;
- cmGlobalGenerator* GG;
- UNORDERED_SET<std::string> Preferred;
-public:
- cmTargetSelectLinker(cmTarget const* target): Preference(0), Target(target)
- {
- this->Makefile = this->Target->GetMakefile();
- this->GG = this->Makefile->GetGlobalGenerator();
- }
- void Consider(const std::string& lang)
- {
- int preference = this->GG->GetLinkerPreference(lang);
- if(preference > this->Preference)
- {
- this->Preference = preference;
- this->Preferred.clear();
- }
- if(preference == this->Preference)
- {
- this->Preferred.insert(lang);
- }
- }
- std::string Choose()
- {
- if(this->Preferred.empty())
- {
- return "";
- }
- else if(this->Preferred.size() > 1)
- {
- std::ostringstream e;
- e << "Target " << this->Target->GetName()
- << " contains multiple languages with the highest linker preference"
- << " (" << this->Preference << "):\n";
- for(UNORDERED_SET<std::string>::const_iterator
- li = this->Preferred.begin(); li != this->Preferred.end(); ++li)
- {
- e << " " << *li << "\n";
- }
- e << "Set the LINKER_LANGUAGE property for this target.";
- cmake* cm = this->Makefile->GetCMakeInstance();
- cm->IssueMessage(cmake::FATAL_ERROR, e.str(),
- this->Target->GetBacktrace());
- }
- return *this->Preferred.begin();
- }
-};
-
-//----------------------------------------------------------------------------
-void cmTarget::ComputeLinkClosure(const std::string& config,
- LinkClosure& lc) const
-{
- // Get languages built in this target.
- UNORDERED_SET<std::string> languages;
- LinkImplementation const* impl = this->GetLinkImplementation(config);
- for(std::vector<std::string>::const_iterator li = impl->Languages.begin();
- li != impl->Languages.end(); ++li)
- {
- languages.insert(*li);
- }
-
- // Add interface languages from linked targets.
- cmTargetCollectLinkLanguages cll(this, config, languages, this);
- for(std::vector<cmLinkImplItem>::const_iterator
- li = impl->Libraries.begin();
- li != impl->Libraries.end(); ++li)
- {
- cll.Visit(*li);
- }
-
- // Store the transitive closure of languages.
- for(UNORDERED_SET<std::string>::const_iterator li = languages.begin();
- li != languages.end(); ++li)
- {
- lc.Languages.push_back(*li);
- }
-
- // Choose the language whose linker should be used.
- if(this->GetProperty("HAS_CXX"))
- {
- lc.LinkerLanguage = "CXX";
- }
- else if(const char* linkerLang = this->GetProperty("LINKER_LANGUAGE"))
- {
- lc.LinkerLanguage = linkerLang;
- }
- else
- {
- // Find the language with the highest preference value.
- cmTargetSelectLinker tsl(this);
-
- // First select from the languages compiled directly in this target.
- for(std::vector<std::string>::const_iterator li = impl->Languages.begin();
- li != impl->Languages.end(); ++li)
- {
- tsl.Consider(*li);
- }
-
- // Now consider languages that propagate from linked targets.
- for(UNORDERED_SET<std::string>::const_iterator sit = languages.begin();
- sit != languages.end(); ++sit)
- {
- std::string propagates = "CMAKE_"+*sit+"_LINKER_PREFERENCE_PROPAGATES";
- if(this->Makefile->IsOn(propagates))
- {
- tsl.Consider(*sit);
- }
- }
-
- lc.LinkerLanguage = tsl.Choose();
- }
-}
-
-//----------------------------------------------------------------------------
void cmTarget::ExpandLinkItems(std::string const& prop,
std::string const& value,
std::string const& config,
@@ -3517,133 +3198,6 @@ const char* cmTarget::GetPrefixVariableInternal(bool implib) const
}
//----------------------------------------------------------------------------
-std::string cmTarget::GetPDBName(const std::string& config) const
-{
- std::string prefix;
- std::string base;
- std::string suffix;
- this->GetFullNameInternal(config, false, prefix, base, suffix);
-
- std::vector<std::string> props;
- std::string configUpper = cmSystemTools::UpperCase(config);
- if(!configUpper.empty())
- {
- // PDB_NAME_<CONFIG>
- props.push_back("PDB_NAME_" + configUpper);
- }
-
- // PDB_NAME
- props.push_back("PDB_NAME");
-
- for(std::vector<std::string>::const_iterator i = props.begin();
- i != props.end(); ++i)
- {
- if(const char* outName = this->GetProperty(*i))
- {
- base = outName;
- break;
- }
- }
- return prefix+base+".pdb";
-}
-
-//----------------------------------------------------------------------------
-std::string cmTarget::GetCompilePDBName(const std::string& config) const
-{
- std::string prefix;
- std::string base;
- std::string suffix;
- this->GetFullNameInternal(config, false, prefix, base, suffix);
-
- // Check for a per-configuration output directory target property.
- std::string configUpper = cmSystemTools::UpperCase(config);
- std::string configProp = "COMPILE_PDB_NAME_";
- configProp += configUpper;
- const char* config_name = this->GetProperty(configProp);
- if(config_name && *config_name)
- {
- return prefix + config_name + ".pdb";
- }
-
- const char* name = this->GetProperty("COMPILE_PDB_NAME");
- if(name && *name)
- {
- return prefix + name + ".pdb";
- }
-
- return "";
-}
-
-//----------------------------------------------------------------------------
-std::string cmTarget::GetCompilePDBPath(const std::string& config) const
-{
- std::string dir = this->GetCompilePDBDirectory(config);
- std::string name = this->GetCompilePDBName(config);
- if(dir.empty() && !name.empty())
- {
- dir = this->GetPDBDirectory(config);
- }
- if(!dir.empty())
- {
- dir += "/";
- }
- return dir + name;
-}
-
-//----------------------------------------------------------------------------
-bool cmTarget::HasSOName(const std::string& config) const
-{
- // soname is supported only for shared libraries and modules,
- // and then only when the platform supports an soname flag.
- return ((this->GetType() == cmTarget::SHARED_LIBRARY ||
- this->GetType() == cmTarget::MODULE_LIBRARY) &&
- !this->GetPropertyAsBool("NO_SONAME") &&
- this->Makefile->GetSONameFlag(this->GetLinkerLanguage(config)));
-}
-
-//----------------------------------------------------------------------------
-std::string cmTarget::GetSOName(const std::string& config) const
-{
- if(this->IsImported())
- {
- // Lookup the imported soname.
- if(cmTarget::ImportInfo const* info = this->GetImportInfo(config))
- {
- if(info->NoSOName)
- {
- // The imported library has no builtin soname so the name
- // searched at runtime will be just the filename.
- return cmSystemTools::GetFilenameName(info->Location);
- }
- else
- {
- // Use the soname given if any.
- if(info->SOName.find("@rpath/") == 0)
- {
- return info->SOName.substr(6);
- }
- return info->SOName;
- }
- }
- else
- {
- return "";
- }
- }
- else
- {
- // Compute the soname that will be built.
- std::string name;
- std::string soName;
- std::string realName;
- std::string impName;
- std::string pdbName;
- this->GetLibraryNames(name, soName, realName, impName, pdbName, config);
- return soName;
- }
-}
-
-//----------------------------------------------------------------------------
bool cmTarget::HasMacOSXRpathInstallNameDir(const std::string& config) const
{
bool install_name_is_rpath = false;
@@ -3770,20 +3324,6 @@ bool cmTarget::IsImportedSharedLibWithoutSOName(
}
//----------------------------------------------------------------------------
-std::string cmTarget::GetFullName(const std::string& config,
- bool implib) const
-{
- if(this->IsImported())
- {
- return this->GetFullNameImported(config, implib);
- }
- else
- {
- return this->GetFullNameInternal(config, implib);
- }
-}
-
-//----------------------------------------------------------------------------
std::string
cmTarget::GetFullNameImported(const std::string& config, bool implib) const
{
@@ -3792,15 +3332,6 @@ cmTarget::GetFullNameImported(const std::string& config, bool implib) const
}
//----------------------------------------------------------------------------
-void cmTarget::GetFullNameComponents(std::string& prefix, std::string& base,
- std::string& suffix,
- const std::string& config,
- bool implib) const
-{
- this->GetFullNameInternal(config, implib, prefix, base, suffix);
-}
-
-//----------------------------------------------------------------------------
std::string
cmTarget::ImportedGetFullPath(const std::string& config, bool implib) const
{
@@ -3818,237 +3349,6 @@ cmTarget::ImportedGetFullPath(const std::string& config, bool implib) const
}
//----------------------------------------------------------------------------
-std::string
-cmTarget::GetFullNameInternal(const std::string& config, bool implib) const
-{
- std::string prefix;
- std::string base;
- std::string suffix;
- this->GetFullNameInternal(config, implib, prefix, base, suffix);
- return prefix+base+suffix;
-}
-
-//----------------------------------------------------------------------------
-void cmTarget::GetFullNameInternal(const std::string& config,
- bool implib,
- std::string& outPrefix,
- std::string& outBase,
- std::string& outSuffix) const
-{
- // Use just the target name for non-main target types.
- if(this->GetType() != cmTarget::STATIC_LIBRARY &&
- this->GetType() != cmTarget::SHARED_LIBRARY &&
- this->GetType() != cmTarget::MODULE_LIBRARY &&
- this->GetType() != cmTarget::EXECUTABLE)
- {
- outPrefix = "";
- outBase = this->GetName();
- outSuffix = "";
- return;
- }
-
- // Return an empty name for the import library if this platform
- // does not support import libraries.
- if(implib &&
- !this->Makefile->GetDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX"))
- {
- outPrefix = "";
- outBase = "";
- outSuffix = "";
- return;
- }
-
- // The implib option is only allowed for shared libraries, module
- // libraries, and executables.
- if(this->GetType() != cmTarget::SHARED_LIBRARY &&
- this->GetType() != cmTarget::MODULE_LIBRARY &&
- this->GetType() != cmTarget::EXECUTABLE)
- {
- implib = false;
- }
-
- // Compute the full name for main target types.
- const char* targetPrefix = (implib
- ? this->GetProperty("IMPORT_PREFIX")
- : this->GetProperty("PREFIX"));
- const char* targetSuffix = (implib
- ? this->GetProperty("IMPORT_SUFFIX")
- : this->GetProperty("SUFFIX"));
- const char* configPostfix = 0;
- if(!config.empty())
- {
- std::string configProp = cmSystemTools::UpperCase(config);
- configProp += "_POSTFIX";
- configPostfix = this->GetProperty(configProp);
- // Mac application bundles and frameworks have no postfix.
- if(configPostfix &&
- (this->IsAppBundleOnApple() || this->IsFrameworkOnApple()))
- {
- configPostfix = 0;
- }
- }
- const char* prefixVar = this->GetPrefixVariableInternal(implib);
- const char* suffixVar = this->GetSuffixVariableInternal(implib);
-
- // Check for language-specific default prefix and suffix.
- std::string ll = this->GetLinkerLanguage(config);
- if(!ll.empty())
- {
- if(!targetSuffix && suffixVar && *suffixVar)
- {
- std::string langSuff = suffixVar + std::string("_") + ll;
- targetSuffix = this->Makefile->GetDefinition(langSuff);
- }
- if(!targetPrefix && prefixVar && *prefixVar)
- {
- std::string langPrefix = prefixVar + std::string("_") + ll;
- targetPrefix = this->Makefile->GetDefinition(langPrefix);
- }
- }
-
- // if there is no prefix on the target use the cmake definition
- if(!targetPrefix && prefixVar)
- {
- targetPrefix = this->Makefile->GetSafeDefinition(prefixVar);
- }
- // if there is no suffix on the target use the cmake definition
- if(!targetSuffix && suffixVar)
- {
- targetSuffix = this->Makefile->GetSafeDefinition(suffixVar);
- }
-
- // frameworks have directory prefix but no suffix
- std::string fw_prefix;
- if(this->IsFrameworkOnApple())
- {
- fw_prefix = this->GetOutputName(config, false);
- fw_prefix += ".framework/";
- targetPrefix = fw_prefix.c_str();
- targetSuffix = 0;
- }
-
- if(this->IsCFBundleOnApple())
- {
- fw_prefix = this->GetCFBundleDirectory(config, false);
- fw_prefix += "/";
- targetPrefix = fw_prefix.c_str();
- targetSuffix = 0;
- }
-
- // Begin the final name with the prefix.
- outPrefix = targetPrefix?targetPrefix:"";
-
- // Append the target name or property-specified name.
- outBase += this->GetOutputName(config, implib);
-
- // Append the per-configuration postfix.
- outBase += configPostfix?configPostfix:"";
-
- // Name shared libraries with their version number on some platforms.
- if(const char* soversion = this->GetProperty("SOVERSION"))
- {
- if(this->GetType() == cmTarget::SHARED_LIBRARY && !implib &&
- this->Makefile->IsOn("CMAKE_SHARED_LIBRARY_NAME_WITH_VERSION"))
- {
- outBase += "-";
- outBase += soversion;
- }
- }
-
- // Append the suffix.
- outSuffix = targetSuffix?targetSuffix:"";
-}
-
-//----------------------------------------------------------------------------
-void cmTarget::GetLibraryNames(std::string& name,
- std::string& soName,
- std::string& realName,
- std::string& impName,
- std::string& pdbName,
- const std::string& config) const
-{
- // This should not be called for imported targets.
- // TODO: Split cmTarget into a class hierarchy to get compile-time
- // enforcement of the limited imported target API.
- if(this->IsImported())
- {
- std::string msg = "GetLibraryNames called on imported target: ";
- msg += this->GetName();
- this->Makefile->IssueMessage(cmake::INTERNAL_ERROR,
- msg);
- return;
- }
-
- assert(this->GetType() != INTERFACE_LIBRARY);
-
- // Check for library version properties.
- const char* version = this->GetProperty("VERSION");
- const char* soversion = this->GetProperty("SOVERSION");
- if(!this->HasSOName(config) ||
- this->Makefile->IsOn("CMAKE_PLATFORM_NO_VERSIONED_SONAME") ||
- this->IsFrameworkOnApple())
- {
- // Versioning is supported only for shared libraries and modules,
- // and then only when the platform supports an soname flag.
- version = 0;
- soversion = 0;
- }
- if(version && !soversion)
- {
- // The soversion must be set if the library version is set. Use
- // the library version as the soversion.
- soversion = version;
- }
- if(!version && soversion)
- {
- // Use the soversion as the library version.
- version = soversion;
- }
-
- // Get the components of the library name.
- std::string prefix;
- std::string base;
- std::string suffix;
- this->GetFullNameInternal(config, false, prefix, base, suffix);
-
- // The library name.
- name = prefix+base+suffix;
-
- if(this->IsFrameworkOnApple())
- {
- realName = prefix;
- realName += "Versions/";
- realName += this->GetFrameworkVersion();
- realName += "/";
- realName += base;
- soName = realName;
- }
- else
- {
- // The library's soname.
- this->ComputeVersionedName(soName, prefix, base, suffix,
- name, soversion);
- // The library's real name on disk.
- this->ComputeVersionedName(realName, prefix, base, suffix,
- name, version);
- }
-
- // The import library name.
- if(this->GetType() == cmTarget::SHARED_LIBRARY ||
- this->GetType() == cmTarget::MODULE_LIBRARY)
- {
- impName = this->GetFullNameInternal(config, true);
- }
- else
- {
- impName = "";
- }
-
- // The program database file name.
- pdbName = this->GetPDBName(config);
-}
-
-//----------------------------------------------------------------------------
void cmTarget::ComputeVersionedName(std::string& vName,
std::string const& prefix,
std::string const& base,
@@ -4066,68 +3366,6 @@ void cmTarget::ComputeVersionedName(std::string& vName,
}
//----------------------------------------------------------------------------
-void cmTarget::GetExecutableNames(std::string& name,
- std::string& realName,
- std::string& impName,
- std::string& pdbName,
- const std::string& config) const
-{
- // This should not be called for imported targets.
- // TODO: Split cmTarget into a class hierarchy to get compile-time
- // enforcement of the limited imported target API.
- if(this->IsImported())
- {
- std::string msg =
- "GetExecutableNames called on imported target: ";
- msg += this->GetName();
- this->GetMakefile()->IssueMessage(cmake::INTERNAL_ERROR, msg);
- }
-
- // This versioning is supported only for executables and then only
- // when the platform supports symbolic links.
-#if defined(_WIN32) && !defined(__CYGWIN__)
- const char* version = 0;
-#else
- // Check for executable version properties.
- const char* version = this->GetProperty("VERSION");
- if(this->GetType() != cmTarget::EXECUTABLE || this->Makefile->IsOn("XCODE"))
- {
- version = 0;
- }
-#endif
-
- // Get the components of the executable name.
- std::string prefix;
- std::string base;
- std::string suffix;
- this->GetFullNameInternal(config, false, prefix, base, suffix);
-
- // The executable name.
- name = prefix+base+suffix;
-
- // The executable's real name on disk.
-#if defined(__CYGWIN__)
- realName = prefix+base;
-#else
- realName = name;
-#endif
- if(version)
- {
- realName += "-";
- realName += version;
- }
-#if defined(__CYGWIN__)
- realName += suffix;
-#endif
-
- // The import library name.
- impName = this->GetFullNameInternal(config, true);
-
- // The program database file name.
- pdbName = this->GetPDBName(config);
-}
-
-//----------------------------------------------------------------------------
bool cmTarget::HasImplibGNUtoMS() const
{
return this->HasImportLibrary() && this->GetPropertyAsBool("GNUtoMS");
@@ -4172,7 +3410,7 @@ bool cmTarget::HaveBuildTreeRPATH(const std::string& config) const
{
return false;
}
- if(LinkImplementationLibraries const* impl =
+ if(cmLinkImplementationLibraries const* impl =
this->GetLinkImplementationLibraries(config))
{
return !impl->Libraries.empty();
@@ -4189,137 +3427,6 @@ bool cmTarget::HaveInstallTreeRPATH() const
}
//----------------------------------------------------------------------------
-bool cmTarget::NeedRelinkBeforeInstall(const std::string& config) const
-{
- // Only executables and shared libraries can have an rpath and may
- // need relinking.
- if(this->TargetTypeValue != cmTarget::EXECUTABLE &&
- this->TargetTypeValue != cmTarget::SHARED_LIBRARY &&
- this->TargetTypeValue != cmTarget::MODULE_LIBRARY)
- {
- return false;
- }
-
- // If there is no install location this target will not be installed
- // and therefore does not need relinking.
- if(!this->GetHaveInstallRule())
- {
- return false;
- }
-
- // If skipping all rpaths completely then no relinking is needed.
- if(this->Makefile->IsOn("CMAKE_SKIP_RPATH"))
- {
- return false;
- }
-
- // If building with the install-tree rpath no relinking is needed.
- if(this->GetPropertyAsBool("BUILD_WITH_INSTALL_RPATH"))
- {
- return false;
- }
-
- // If chrpath is going to be used no relinking is needed.
- if(this->IsChrpathUsed(config))
- {
- return false;
- }
-
- // Check for rpath support on this platform.
- std::string ll = this->GetLinkerLanguage(config);
- if(!ll.empty())
- {
- std::string flagVar = "CMAKE_SHARED_LIBRARY_RUNTIME_";
- flagVar += ll;
- flagVar += "_FLAG";
- if(!this->Makefile->IsSet(flagVar))
- {
- // There is no rpath support on this platform so nothing needs
- // relinking.
- return false;
- }
- }
- else
- {
- // No linker language is known. This error will be reported by
- // other code.
- return false;
- }
-
- // If either a build or install tree rpath is set then the rpath
- // will likely change between the build tree and install tree and
- // this target must be relinked.
- return this->HaveBuildTreeRPATH(config) || this->HaveInstallTreeRPATH();
-}
-
-//----------------------------------------------------------------------------
-std::string cmTarget::GetInstallNameDirForBuildTree(
- const std::string& config) const
-{
- // If building directly for installation then the build tree install_name
- // is the same as the install tree.
- if(this->GetPropertyAsBool("BUILD_WITH_INSTALL_RPATH"))
- {
- return GetInstallNameDirForInstallTree();
- }
-
- // Use the build tree directory for the target.
- if(this->Makefile->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME") &&
- !this->Makefile->IsOn("CMAKE_SKIP_RPATH") &&
- !this->GetPropertyAsBool("SKIP_BUILD_RPATH"))
- {
- std::string dir;
- bool macosx_rpath = this->MacOSXRpathInstallNameDirDefault();
- if(macosx_rpath)
- {
- dir = "@rpath";
- }
- else
- {
- dir = this->GetDirectory(config);
- }
- dir += "/";
- return dir;
- }
- else
- {
- return "";
- }
-}
-
-//----------------------------------------------------------------------------
-std::string cmTarget::GetInstallNameDirForInstallTree() const
-{
- if(this->Makefile->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME"))
- {
- std::string dir;
- const char* install_name_dir = this->GetProperty("INSTALL_NAME_DIR");
-
- if(!this->Makefile->IsOn("CMAKE_SKIP_RPATH") &&
- !this->Makefile->IsOn("CMAKE_SKIP_INSTALL_RPATH"))
- {
- if(install_name_dir && *install_name_dir)
- {
- dir = install_name_dir;
- dir += "/";
- }
- }
- if(!install_name_dir)
- {
- if(this->MacOSXRpathInstallNameDirDefault())
- {
- dir = "@rpath/";
- }
- }
- return dir;
- }
- else
- {
- return "";
- }
-}
-
-//----------------------------------------------------------------------------
const char* cmTarget::GetOutputTargetType(bool implib) const
{
switch(this->GetType())
@@ -4408,7 +3515,10 @@ bool cmTarget::ComputeOutputDir(const std::string& config,
if(const char* config_outdir = this->GetProperty(configProp))
{
// Use the user-specified per-configuration output directory.
- out = config_outdir;
+ cmGeneratorExpression ge;
+ cmsys::auto_ptr<cmCompiledGeneratorExpression> cge =
+ ge.Parse(config_outdir);
+ out = cge->Evaluate(this->Makefile, config);
// Skip per-configuration subdirectory.
conf = "";
@@ -4416,7 +3526,17 @@ bool cmTarget::ComputeOutputDir(const std::string& config,
else if(const char* outdir = this->GetProperty(propertyName))
{
// Use the user-specified output directory.
- out = outdir;
+ cmGeneratorExpression ge;
+ cmsys::auto_ptr<cmCompiledGeneratorExpression> cge =
+ ge.Parse(outdir);
+ out = cge->Evaluate(this->Makefile, config);
+
+ // Skip per-configuration subdirectory if the value contained a
+ // generator expression.
+ if (out != outdir)
+ {
+ conf = "";
+ }
}
else if(this->GetType() == cmTarget::EXECUTABLE)
{
@@ -4527,54 +3647,6 @@ bool cmTarget::UsesDefaultOutputDir(const std::string& config,
}
//----------------------------------------------------------------------------
-std::string cmTarget::GetOutputName(const std::string& config,
- bool implib) const
-{
- std::vector<std::string> props;
- std::string type = this->GetOutputTargetType(implib);
- std::string configUpper = cmSystemTools::UpperCase(config);
- if(!type.empty() && !configUpper.empty())
- {
- // <ARCHIVE|LIBRARY|RUNTIME>_OUTPUT_NAME_<CONFIG>
- props.push_back(type + "_OUTPUT_NAME_" + configUpper);
- }
- if(!type.empty())
- {
- // <ARCHIVE|LIBRARY|RUNTIME>_OUTPUT_NAME
- props.push_back(type + "_OUTPUT_NAME");
- }
- if(!configUpper.empty())
- {
- // OUTPUT_NAME_<CONFIG>
- props.push_back("OUTPUT_NAME_" + configUpper);
- // <CONFIG>_OUTPUT_NAME
- props.push_back(configUpper + "_OUTPUT_NAME");
- }
- // OUTPUT_NAME
- props.push_back("OUTPUT_NAME");
-
- std::string outName;
- for(std::vector<std::string>::const_iterator i = props.begin();
- i != props.end(); ++i)
- {
- if (const char* outNameProp = this->GetProperty(*i))
- {
- outName = outNameProp;
- break;
- }
- }
-
- if (outName.empty())
- {
- outName = this->GetName();
- }
-
- cmGeneratorExpression ge;
- cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(outName);
- return cge->Evaluate(this->Makefile, config);
-}
-
-//----------------------------------------------------------------------------
std::string cmTarget::GetFrameworkVersion() const
{
assert(this->GetType() != INTERFACE_LIBRARY);
@@ -4627,500 +3699,6 @@ bool cmTarget::IsNullImpliedByLinkLibraries(const std::string &p) const
}
//----------------------------------------------------------------------------
-template<typename PropertyType>
-PropertyType getTypedProperty(cmTarget const* tgt, const std::string& prop);
-
-//----------------------------------------------------------------------------
-template<>
-bool getTypedProperty<bool>(cmTarget const* tgt, const std::string& prop)
-{
- return tgt->GetPropertyAsBool(prop);
-}
-
-//----------------------------------------------------------------------------
-template<>
-const char *getTypedProperty<const char *>(cmTarget const* tgt,
- const std::string& prop)
-{
- return tgt->GetProperty(prop);
-}
-
-enum CompatibleType
-{
- BoolType,
- StringType,
- NumberMinType,
- NumberMaxType
-};
-
-//----------------------------------------------------------------------------
-template<typename PropertyType>
-std::pair<bool, PropertyType> consistentProperty(PropertyType lhs,
- PropertyType rhs,
- CompatibleType t);
-
-//----------------------------------------------------------------------------
-template<>
-std::pair<bool, bool> consistentProperty(bool lhs, bool rhs, CompatibleType)
-{
- return std::make_pair(lhs == rhs, lhs);
-}
-
-//----------------------------------------------------------------------------
-std::pair<bool, const char*> consistentStringProperty(const char *lhs,
- const char *rhs)
-{
- const bool b = strcmp(lhs, rhs) == 0;
- return std::make_pair(b, b ? lhs : 0);
-}
-
-//----------------------------------------------------------------------------
-std::pair<bool, const char*> consistentNumberProperty(const char *lhs,
- const char *rhs,
- CompatibleType t)
-{
- char *pEnd;
-
- const char* const null_ptr = 0;
-
- long lnum = strtol(lhs, &pEnd, 0);
- if (pEnd == lhs || *pEnd != '\0' || errno == ERANGE)
- {
- return std::pair<bool, const char*>(false, null_ptr);
- }
-
- long rnum = strtol(rhs, &pEnd, 0);
- if (pEnd == rhs || *pEnd != '\0' || errno == ERANGE)
- {
- return std::pair<bool, const char*>(false, null_ptr);
- }
-
- if (t == NumberMaxType)
- {
- return std::make_pair(true, std::max(lnum, rnum) == lnum ? lhs : rhs);
- }
- else
- {
- return std::make_pair(true, std::min(lnum, rnum) == lnum ? lhs : rhs);
- }
-}
-
-//----------------------------------------------------------------------------
-template<>
-std::pair<bool, const char*> consistentProperty(const char *lhs,
- const char *rhs,
- CompatibleType t)
-{
- if (!lhs && !rhs)
- {
- return std::make_pair(true, lhs);
- }
- if (!lhs)
- {
- return std::make_pair(true, rhs);
- }
- if (!rhs)
- {
- return std::make_pair(true, lhs);
- }
-
- const char* const null_ptr = 0;
-
- switch(t)
- {
- case BoolType:
- assert(0 && "consistentProperty for strings called with BoolType");
- return std::pair<bool, const char*>(false, null_ptr);
- case StringType:
- return consistentStringProperty(lhs, rhs);
- case NumberMinType:
- case NumberMaxType:
- return consistentNumberProperty(lhs, rhs, t);
- }
- assert(0 && "Unreachable!");
- return std::pair<bool, const char*>(false, null_ptr);
-}
-
-template<typename PropertyType>
-PropertyType impliedValue(PropertyType);
-template<>
-bool impliedValue<bool>(bool)
-{
- return false;
-}
-template<>
-const char* impliedValue<const char*>(const char*)
-{
- return "";
-}
-
-
-template<typename PropertyType>
-std::string valueAsString(PropertyType);
-template<>
-std::string valueAsString<bool>(bool value)
-{
- return value ? "TRUE" : "FALSE";
-}
-template<>
-std::string valueAsString<const char*>(const char* value)
-{
- return value ? value : "(unset)";
-}
-
-//----------------------------------------------------------------------------
-void
-cmTarget::ReportPropertyOrigin(const std::string &p,
- const std::string &result,
- const std::string &report,
- const std::string &compatibilityType) const
-{
- std::vector<std::string> debugProperties;
- const char *debugProp =
- this->Makefile->GetDefinition("CMAKE_DEBUG_TARGET_PROPERTIES");
- if (debugProp)
- {
- cmSystemTools::ExpandListArgument(debugProp, debugProperties);
- }
-
- bool debugOrigin = !this->DebugCompatiblePropertiesDone[p]
- && std::find(debugProperties.begin(),
- debugProperties.end(),
- p)
- != debugProperties.end();
-
- if (this->Makefile->IsConfigured())
- {
- this->DebugCompatiblePropertiesDone[p] = true;
- }
- if (!debugOrigin)
- {
- return;
- }
-
- std::string areport = compatibilityType;
- areport += std::string(" of property \"") + p + "\" for target \"";
- areport += std::string(this->GetName());
- areport += "\" (result: \"";
- areport += result;
- areport += "\"):\n" + report;
-
- this->Makefile->GetCMakeInstance()->IssueMessage(cmake::LOG, areport);
-}
-
-//----------------------------------------------------------------------------
-std::string compatibilityType(CompatibleType t)
-{
- switch(t)
- {
- case BoolType:
- return "Boolean compatibility";
- case StringType:
- return "String compatibility";
- case NumberMaxType:
- return "Numeric maximum compatibility";
- case NumberMinType:
- return "Numeric minimum compatibility";
- }
- assert(0 && "Unreachable!");
- return "";
-}
-
-//----------------------------------------------------------------------------
-std::string compatibilityAgree(CompatibleType t, bool dominant)
-{
- switch(t)
- {
- case BoolType:
- case StringType:
- return dominant ? "(Disagree)\n" : "(Agree)\n";
- case NumberMaxType:
- case NumberMinType:
- return dominant ? "(Dominant)\n" : "(Ignored)\n";
- }
- assert(0 && "Unreachable!");
- return "";
-}
-
-//----------------------------------------------------------------------------
-template<typename PropertyType>
-PropertyType checkInterfacePropertyCompatibility(cmTarget const* tgt,
- const std::string &p,
- const std::string& config,
- const char *defaultValue,
- CompatibleType t,
- PropertyType *)
-{
- PropertyType propContent = getTypedProperty<PropertyType>(tgt, p);
- const bool explicitlySet = tgt->GetProperties()
- .find(p)
- != tgt->GetProperties().end();
- const bool impliedByUse =
- tgt->IsNullImpliedByLinkLibraries(p);
- assert((impliedByUse ^ explicitlySet)
- || (!impliedByUse && !explicitlySet));
-
- std::vector<cmTarget const*> const& deps =
- tgt->GetLinkImplementationClosure(config);
-
- if(deps.empty())
- {
- return propContent;
- }
- bool propInitialized = explicitlySet;
-
- std::string report = " * Target \"";
- report += tgt->GetName();
- if (explicitlySet)
- {
- report += "\" has property content \"";
- report += valueAsString<PropertyType>(propContent);
- report += "\"\n";
- }
- else if (impliedByUse)
- {
- report += "\" property is implied by use.\n";
- }
- else
- {
- report += "\" property not set.\n";
- }
-
- std::string interfaceProperty = "INTERFACE_" + p;
- for(std::vector<cmTarget const*>::const_iterator li =
- deps.begin();
- li != deps.end(); ++li)
- {
- // An error should be reported if one dependency
- // has INTERFACE_POSITION_INDEPENDENT_CODE ON and the other
- // has INTERFACE_POSITION_INDEPENDENT_CODE OFF, or if the
- // target itself has a POSITION_INDEPENDENT_CODE which disagrees
- // with a dependency.
-
- cmTarget const* theTarget = *li;
-
- const bool ifaceIsSet = theTarget->GetProperties()
- .find(interfaceProperty)
- != theTarget->GetProperties().end();
- PropertyType ifacePropContent =
- getTypedProperty<PropertyType>(theTarget,
- interfaceProperty);
-
- std::string reportEntry;
- if (ifaceIsSet)
- {
- reportEntry += " * Target \"";
- reportEntry += theTarget->GetName();
- reportEntry += "\" property value \"";
- reportEntry += valueAsString<PropertyType>(ifacePropContent);
- reportEntry += "\" ";
- }
-
- if (explicitlySet)
- {
- if (ifaceIsSet)
- {
- std::pair<bool, PropertyType> consistent =
- consistentProperty(propContent,
- ifacePropContent, t);
- report += reportEntry;
- report += compatibilityAgree(t, propContent != consistent.second);
- if (!consistent.first)
- {
- std::ostringstream e;
- e << "Property " << p << " on target \""
- << tgt->GetName() << "\" does\nnot match the "
- "INTERFACE_" << p << " property requirement\nof "
- "dependency \"" << theTarget->GetName() << "\".\n";
- cmSystemTools::Error(e.str().c_str());
- break;
- }
- else
- {
- propContent = consistent.second;
- continue;
- }
- }
- else
- {
- // Explicitly set on target and not set in iface. Can't disagree.
- continue;
- }
- }
- else if (impliedByUse)
- {
- propContent = impliedValue<PropertyType>(propContent);
-
- if (ifaceIsSet)
- {
- std::pair<bool, PropertyType> consistent =
- consistentProperty(propContent,
- ifacePropContent, t);
- report += reportEntry;
- report += compatibilityAgree(t, propContent != consistent.second);
- if (!consistent.first)
- {
- std::ostringstream e;
- e << "Property " << p << " on target \""
- << tgt->GetName() << "\" is\nimplied to be " << defaultValue
- << " because it was used to determine the link libraries\n"
- "already. The INTERFACE_" << p << " property on\ndependency \""
- << theTarget->GetName() << "\" is in conflict.\n";
- cmSystemTools::Error(e.str().c_str());
- break;
- }
- else
- {
- propContent = consistent.second;
- continue;
- }
- }
- else
- {
- // Implicitly set on target and not set in iface. Can't disagree.
- continue;
- }
- }
- else
- {
- if (ifaceIsSet)
- {
- if (propInitialized)
- {
- std::pair<bool, PropertyType> consistent =
- consistentProperty(propContent,
- ifacePropContent, t);
- report += reportEntry;
- report += compatibilityAgree(t, propContent != consistent.second);
- if (!consistent.first)
- {
- std::ostringstream e;
- e << "The INTERFACE_" << p << " property of \""
- << theTarget->GetName() << "\" does\nnot agree with the value "
- "of " << p << " already determined\nfor \""
- << tgt->GetName() << "\".\n";
- cmSystemTools::Error(e.str().c_str());
- break;
- }
- else
- {
- propContent = consistent.second;
- continue;
- }
- }
- else
- {
- report += reportEntry + "(Interface set)\n";
- propContent = ifacePropContent;
- propInitialized = true;
- }
- }
- else
- {
- // Not set. Nothing to agree on.
- continue;
- }
- }
- }
-
- tgt->ReportPropertyOrigin(p, valueAsString<PropertyType>(propContent),
- report, compatibilityType(t));
- return propContent;
-}
-
-//----------------------------------------------------------------------------
-bool cmTarget::GetLinkInterfaceDependentBoolProperty(const std::string &p,
- const std::string& config) const
-{
- return checkInterfacePropertyCompatibility<bool>(this, p, config, "FALSE",
- BoolType, 0);
-}
-
-//----------------------------------------------------------------------------
-const char * cmTarget::GetLinkInterfaceDependentStringProperty(
- const std::string &p,
- const std::string& config) const
-{
- return checkInterfacePropertyCompatibility<const char *>(this,
- p,
- config,
- "empty",
- StringType, 0);
-}
-
-//----------------------------------------------------------------------------
-const char * cmTarget::GetLinkInterfaceDependentNumberMinProperty(
- const std::string &p,
- const std::string& config) const
-{
- return checkInterfacePropertyCompatibility<const char *>(this,
- p,
- config,
- "empty",
- NumberMinType, 0);
-}
-
-//----------------------------------------------------------------------------
-const char * cmTarget::GetLinkInterfaceDependentNumberMaxProperty(
- const std::string &p,
- const std::string& config) const
-{
- return checkInterfacePropertyCompatibility<const char *>(this,
- p,
- config,
- "empty",
- NumberMaxType, 0);
-}
-
-//----------------------------------------------------------------------------
-bool cmTarget::IsLinkInterfaceDependentBoolProperty(const std::string &p,
- const std::string& config) const
-{
- if (this->TargetTypeValue == OBJECT_LIBRARY
- || this->TargetTypeValue == INTERFACE_LIBRARY)
- {
- return false;
- }
- return this->GetCompatibleInterfaces(config).PropsBool.count(p) > 0;
-}
-
-//----------------------------------------------------------------------------
-bool cmTarget::IsLinkInterfaceDependentStringProperty(const std::string &p,
- const std::string& config) const
-{
- if (this->TargetTypeValue == OBJECT_LIBRARY
- || this->TargetTypeValue == INTERFACE_LIBRARY)
- {
- return false;
- }
- return this->GetCompatibleInterfaces(config).PropsString.count(p) > 0;
-}
-
-//----------------------------------------------------------------------------
-bool cmTarget::IsLinkInterfaceDependentNumberMinProperty(const std::string &p,
- const std::string& config) const
-{
- if (this->TargetTypeValue == OBJECT_LIBRARY
- || this->TargetTypeValue == INTERFACE_LIBRARY)
- {
- return false;
- }
- return this->GetCompatibleInterfaces(config).PropsNumberMin.count(p) > 0;
-}
-
-//----------------------------------------------------------------------------
-bool cmTarget::IsLinkInterfaceDependentNumberMaxProperty(const std::string &p,
- const std::string& config) const
-{
- if (this->TargetTypeValue == OBJECT_LIBRARY
- || this->TargetTypeValue == INTERFACE_LIBRARY)
- {
- return false;
- }
- return this->GetCompatibleInterfaces(config).PropsNumberMax.count(p) > 0;
-}
-
-//----------------------------------------------------------------------------
void
cmTarget::GetObjectLibrariesCMP0026(std::vector<cmTarget*>& objlibs) const
{
@@ -5206,73 +3784,6 @@ void cmTarget::GetLanguages(std::set<std::string>& languages,
}
//----------------------------------------------------------------------------
-bool cmTarget::IsChrpathUsed(const std::string& config) const
-{
- // Only certain target types have an rpath.
- if(!(this->GetType() == cmTarget::SHARED_LIBRARY ||
- this->GetType() == cmTarget::MODULE_LIBRARY ||
- this->GetType() == cmTarget::EXECUTABLE))
- {
- return false;
- }
-
- // If the target will not be installed we do not need to change its
- // rpath.
- if(!this->GetHaveInstallRule())
- {
- return false;
- }
-
- // Skip chrpath if skipping rpath altogether.
- if(this->Makefile->IsOn("CMAKE_SKIP_RPATH"))
- {
- return false;
- }
-
- // Skip chrpath if it does not need to be changed at install time.
- if(this->GetPropertyAsBool("BUILD_WITH_INSTALL_RPATH"))
- {
- return false;
- }
-
- // Allow the user to disable builtin chrpath explicitly.
- if(this->Makefile->IsOn("CMAKE_NO_BUILTIN_CHRPATH"))
- {
- return false;
- }
-
- if(this->Makefile->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME"))
- {
- return true;
- }
-
-#if defined(CMAKE_USE_ELF_PARSER)
- // Enable if the rpath flag uses a separator and the target uses ELF
- // binaries.
- std::string ll = this->GetLinkerLanguage(config);
- if(!ll.empty())
- {
- std::string sepVar = "CMAKE_SHARED_LIBRARY_RUNTIME_";
- sepVar += ll;
- sepVar += "_FLAG_SEP";
- const char* sep = this->Makefile->GetDefinition(sepVar);
- if(sep && *sep)
- {
- // TODO: Add ELF check to ABI detection and get rid of
- // CMAKE_EXECUTABLE_FORMAT.
- if(const char* fmt =
- this->Makefile->GetDefinition("CMAKE_EXECUTABLE_FORMAT"))
- {
- return strcmp(fmt, "ELF") == 0;
- }
- }
- }
-#endif
- static_cast<void>(config);
- return false;
-}
-
-//----------------------------------------------------------------------------
cmTarget::ImportInfo const*
cmTarget::GetImportInfo(const std::string& config) const
{
@@ -5760,86 +4271,6 @@ cmTarget::GetImportLinkInterface(const std::string& config,
}
//----------------------------------------------------------------------------
-void processILibs(const std::string& config,
- cmTarget const* headTarget,
- cmLinkItem const& item,
- std::vector<cmTarget const*>& tgts,
- std::set<cmTarget const*>& emitted)
-{
- if (item.Target && emitted.insert(item.Target).second)
- {
- tgts.push_back(item.Target);
- if(cmTarget::LinkInterfaceLibraries const* iface =
- item.Target->GetLinkInterfaceLibraries(config, headTarget, true))
- {
- for(std::vector<cmLinkItem>::const_iterator
- it = iface->Libraries.begin();
- it != iface->Libraries.end(); ++it)
- {
- processILibs(config, headTarget, *it, tgts, emitted);
- }
- }
- }
-}
-
-//----------------------------------------------------------------------------
-std::vector<cmTarget const*> const&
-cmTarget::GetLinkImplementationClosure(const std::string& config) const
-{
- cmTargetInternals::LinkImplClosure& tgts =
- this->Internal->LinkImplClosureMap[config];
- if(!tgts.Done)
- {
- tgts.Done = true;
- std::set<cmTarget const*> emitted;
-
- cmTarget::LinkImplementationLibraries const* impl
- = this->GetLinkImplementationLibraries(config);
-
- for(std::vector<cmLinkImplItem>::const_iterator
- it = impl->Libraries.begin();
- it != impl->Libraries.end(); ++it)
- {
- processILibs(config, this, *it, tgts , emitted);
- }
- }
- return tgts;
-}
-
-//----------------------------------------------------------------------------
-cmTarget::CompatibleInterfaces const&
-cmTarget::GetCompatibleInterfaces(std::string const& config) const
-{
- cmTargetInternals::CompatibleInterfaces& compat =
- this->Internal->CompatibleInterfacesMap[config];
- if(!compat.Done)
- {
- compat.Done = true;
- compat.PropsBool.insert("POSITION_INDEPENDENT_CODE");
- compat.PropsString.insert("AUTOUIC_OPTIONS");
- std::vector<cmTarget const*> const& deps =
- this->GetLinkImplementationClosure(config);
- for(std::vector<cmTarget const*>::const_iterator li = deps.begin();
- li != deps.end(); ++li)
- {
-#define CM_READ_COMPATIBLE_INTERFACE(X, x) \
- if(const char* prop = (*li)->GetProperty("COMPATIBLE_INTERFACE_" #X)) \
- { \
- std::vector<std::string> props; \
- cmSystemTools::ExpandListArgument(prop, props); \
- compat.Props##x.insert(props.begin(), props.end()); \
- }
- CM_READ_COMPATIBLE_INTERFACE(BOOL, Bool)
- CM_READ_COMPATIBLE_INTERFACE(STRING, String)
- CM_READ_COMPATIBLE_INTERFACE(NUMBER_MIN, NumberMin)
- CM_READ_COMPATIBLE_INTERFACE(NUMBER_MAX, NumberMax)
-#undef CM_READ_COMPATIBLE_INTERFACE
- }
- }
- return compat;
-}
-
-//----------------------------------------------------------------------------
void
cmTargetInternals::ComputeLinkInterfaceLibraries(
cmTarget const* thisTarget,
@@ -5942,7 +4373,7 @@ cmTargetInternals::ComputeLinkInterfaceLibraries(
// to the link implementation.
{
// The link implementation is the default link interface.
- cmTarget::LinkImplementationLibraries const* impl =
+ cmLinkImplementationLibraries const* impl =
thisTarget->GetLinkImplementationLibrariesInternal(config, headTarget);
iface.Libraries.insert(iface.Libraries.end(),
impl->Libraries.begin(), impl->Libraries.end());
@@ -6042,7 +4473,7 @@ void cmTargetInternals::ComputeLinkInterface(cmTarget const* thisTarget,
|| thisTarget->GetPolicyStatusCMP0022() == cmPolicies::OLD)
{
// The link implementation is the default link interface.
- cmTarget::LinkImplementationLibraries const*
+ cmLinkImplementationLibraries const*
impl = thisTarget->GetLinkImplementationLibrariesInternal(config,
headTarget);
iface.ImplementationIsInterface = true;
@@ -6093,7 +4524,7 @@ void cmTargetInternals::AddInterfaceEntries(
cmTarget const* thisTarget, std::string const& config,
std::string const& prop, std::vector<TargetPropertyEntry*>& entries)
{
- if(cmTarget::LinkImplementationLibraries const* impl =
+ if(cmLinkImplementationLibraries const* impl =
thisTarget->GetLinkImplementationLibraries(config))
{
for (std::vector<cmLinkImplItem>::const_iterator
@@ -6143,14 +4574,14 @@ cmTarget::GetLinkImplementation(const std::string& config) const
}
//----------------------------------------------------------------------------
-cmTarget::LinkImplementationLibraries const*
+cmLinkImplementationLibraries const*
cmTarget::GetLinkImplementationLibraries(const std::string& config) const
{
return this->GetLinkImplementationLibrariesInternal(config, this);
}
//----------------------------------------------------------------------------
-cmTarget::LinkImplementationLibraries const*
+cmLinkImplementationLibraries const*
cmTarget::GetLinkImplementationLibrariesInternal(const std::string& config,
cmTarget const* head) const
{
@@ -6396,382 +4827,6 @@ std::string cmTarget::CheckCMP0004(std::string const& item) const
return lib;
}
-template<typename PropertyType>
-PropertyType getLinkInterfaceDependentProperty(cmTarget const* tgt,
- const std::string& prop,
- const std::string& config,
- CompatibleType,
- PropertyType *);
-
-template<>
-bool getLinkInterfaceDependentProperty(cmTarget const* tgt,
- const std::string& prop,
- const std::string& config,
- CompatibleType, bool *)
-{
- return tgt->GetLinkInterfaceDependentBoolProperty(prop, config);
-}
-
-template<>
-const char * getLinkInterfaceDependentProperty(cmTarget const* tgt,
- const std::string& prop,
- const std::string& config,
- CompatibleType t,
- const char **)
-{
- switch(t)
- {
- case BoolType:
- assert(0 && "String compatibility check function called for boolean");
- return 0;
- case StringType:
- return tgt->GetLinkInterfaceDependentStringProperty(prop, config);
- case NumberMinType:
- return tgt->GetLinkInterfaceDependentNumberMinProperty(prop, config);
- case NumberMaxType:
- return tgt->GetLinkInterfaceDependentNumberMaxProperty(prop, config);
- }
- assert(0 && "Unreachable!");
- return 0;
-}
-
-//----------------------------------------------------------------------------
-template<typename PropertyType>
-void checkPropertyConsistency(cmTarget const* depender,
- cmTarget const* dependee,
- const std::string& propName,
- std::set<std::string> &emitted,
- const std::string& config,
- CompatibleType t,
- PropertyType *)
-{
- const char *prop = dependee->GetProperty(propName);
- if (!prop)
- {
- return;
- }
-
- std::vector<std::string> props;
- cmSystemTools::ExpandListArgument(prop, props);
- std::string pdir =
- dependee->GetMakefile()->GetRequiredDefinition("CMAKE_ROOT");
- pdir += "/Help/prop_tgt/";
-
- for(std::vector<std::string>::iterator pi = props.begin();
- pi != props.end(); ++pi)
- {
- std::string pname = cmSystemTools::HelpFileName(*pi);
- std::string pfile = pdir + pname + ".rst";
- if(cmSystemTools::FileExists(pfile.c_str(), true))
- {
- std::ostringstream e;
- e << "Target \"" << dependee->GetName() << "\" has property \""
- << *pi << "\" listed in its " << propName << " property. "
- "This is not allowed. Only user-defined properties may appear "
- "listed in the " << propName << " property.";
- depender->GetMakefile()->IssueMessage(cmake::FATAL_ERROR, e.str());
- return;
- }
- if(emitted.insert(*pi).second)
- {
- getLinkInterfaceDependentProperty<PropertyType>(depender, *pi, config,
- t, 0);
- if (cmSystemTools::GetErrorOccuredFlag())
- {
- return;
- }
- }
- }
-}
-
-static std::string intersect(const std::set<std::string> &s1,
- const std::set<std::string> &s2)
-{
- std::set<std::string> intersect;
- std::set_intersection(s1.begin(),s1.end(),
- s2.begin(),s2.end(),
- std::inserter(intersect,intersect.begin()));
- if (!intersect.empty())
- {
- return *intersect.begin();
- }
- return "";
-}
-static std::string intersect(const std::set<std::string> &s1,
- const std::set<std::string> &s2,
- const std::set<std::string> &s3)
-{
- std::string result;
- result = intersect(s1, s2);
- if (!result.empty())
- return result;
- result = intersect(s1, s3);
- if (!result.empty())
- return result;
- return intersect(s2, s3);
-}
-static std::string intersect(const std::set<std::string> &s1,
- const std::set<std::string> &s2,
- const std::set<std::string> &s3,
- const std::set<std::string> &s4)
-{
- std::string result;
- result = intersect(s1, s2);
- if (!result.empty())
- return result;
- result = intersect(s1, s3);
- if (!result.empty())
- return result;
- result = intersect(s1, s4);
- if (!result.empty())
- return result;
- return intersect(s2, s3, s4);
-}
-
-//----------------------------------------------------------------------------
-void cmTarget::CheckPropertyCompatibility(cmComputeLinkInformation *info,
- const std::string& config) const
-{
- const cmComputeLinkInformation::ItemVector &deps = info->GetItems();
-
- std::set<std::string> emittedBools;
- static std::string strBool = "COMPATIBLE_INTERFACE_BOOL";
- std::set<std::string> emittedStrings;
- static std::string strString = "COMPATIBLE_INTERFACE_STRING";
- std::set<std::string> emittedMinNumbers;
- static std::string strNumMin = "COMPATIBLE_INTERFACE_NUMBER_MIN";
- std::set<std::string> emittedMaxNumbers;
- static std::string strNumMax = "COMPATIBLE_INTERFACE_NUMBER_MAX";
-
- for(cmComputeLinkInformation::ItemVector::const_iterator li =
- deps.begin();
- li != deps.end(); ++li)
- {
- if (!li->Target)
- {
- continue;
- }
-
- checkPropertyConsistency<bool>(this, li->Target,
- strBool,
- emittedBools, config, BoolType, 0);
- if (cmSystemTools::GetErrorOccuredFlag())
- {
- return;
- }
- checkPropertyConsistency<const char *>(this, li->Target,
- strString,
- emittedStrings, config,
- StringType, 0);
- if (cmSystemTools::GetErrorOccuredFlag())
- {
- return;
- }
- checkPropertyConsistency<const char *>(this, li->Target,
- strNumMin,
- emittedMinNumbers, config,
- NumberMinType, 0);
- if (cmSystemTools::GetErrorOccuredFlag())
- {
- return;
- }
- checkPropertyConsistency<const char *>(this, li->Target,
- strNumMax,
- emittedMaxNumbers, config,
- NumberMaxType, 0);
- if (cmSystemTools::GetErrorOccuredFlag())
- {
- return;
- }
- }
-
- std::string prop = intersect(emittedBools,
- emittedStrings,
- emittedMinNumbers,
- emittedMaxNumbers);
-
- if (!prop.empty())
- {
- // Use a sorted std::vector to keep the error message sorted.
- std::vector<std::string> props;
- std::set<std::string>::const_iterator i = emittedBools.find(prop);
- if (i != emittedBools.end())
- {
- props.push_back(strBool);
- }
- i = emittedStrings.find(prop);
- if (i != emittedStrings.end())
- {
- props.push_back(strString);
- }
- i = emittedMinNumbers.find(prop);
- if (i != emittedMinNumbers.end())
- {
- props.push_back(strNumMin);
- }
- i = emittedMaxNumbers.find(prop);
- if (i != emittedMaxNumbers.end())
- {
- props.push_back(strNumMax);
- }
- std::sort(props.begin(), props.end());
-
- std::string propsString = cmJoin(cmMakeRange(props).retreat(1), ", ");
- propsString += " and the " + props.back();
-
- std::ostringstream e;
- e << "Property \"" << prop << "\" appears in both the "
- << propsString <<
- " property in the dependencies of target \"" << this->GetName() <<
- "\". This is not allowed. A property may only require compatibility "
- "in a boolean interpretation, a numeric minimum, a numeric maximum or a "
- "string interpretation, but not a mixture.";
- this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
- }
-}
-
-//----------------------------------------------------------------------------
-cmComputeLinkInformation*
-cmTarget::GetLinkInformation(const std::string& config) const
-{
- // Lookup any existing information for this configuration.
- std::string key(cmSystemTools::UpperCase(config));
- cmTargetLinkInformationMap::iterator
- i = this->LinkInformation.find(key);
- if(i == this->LinkInformation.end())
- {
- // Compute information for this configuration.
- cmComputeLinkInformation* info =
- new cmComputeLinkInformation(this, config);
- if(!info || !info->Compute())
- {
- delete info;
- info = 0;
- }
-
- // Store the information for this configuration.
- cmTargetLinkInformationMap::value_type entry(key, info);
- i = this->LinkInformation.insert(entry).first;
-
- if (info)
- {
- this->CheckPropertyCompatibility(info, config);
- }
- }
- return i->second;
-}
-
-//----------------------------------------------------------------------------
-std::string cmTarget::GetFrameworkDirectory(const std::string& config,
- bool rootDir) const
-{
- std::string fpath;
- fpath += this->GetOutputName(config, false);
- fpath += ".framework";
- if(!rootDir)
- {
- fpath += "/Versions/";
- fpath += this->GetFrameworkVersion();
- }
- return fpath;
-}
-
-//----------------------------------------------------------------------------
-std::string cmTarget::GetCFBundleDirectory(const std::string& config,
- bool contentOnly) const
-{
- std::string fpath;
- fpath += this->GetOutputName(config, false);
- fpath += ".";
- const char *ext = this->GetProperty("BUNDLE_EXTENSION");
- if (!ext)
- {
- if (this->IsXCTestOnApple())
- {
- ext = "xctest";
- }
- else
- {
- ext = "bundle";
- }
- }
- fpath += ext;
- fpath += "/Contents";
- if(!contentOnly)
- fpath += "/MacOS";
- return fpath;
-}
-
-//----------------------------------------------------------------------------
-std::string cmTarget::GetAppBundleDirectory(const std::string& config,
- bool contentOnly) const
-{
- std::string fpath = this->GetFullName(config, false);
- fpath += ".app/Contents";
- if(!contentOnly)
- fpath += "/MacOS";
- return fpath;
-}
-
-//----------------------------------------------------------------------------
-std::string cmTarget::BuildMacContentDirectory(const std::string& base,
- const std::string& config,
- bool contentOnly) const
-{
- std::string fpath = base;
- if(this->IsAppBundleOnApple())
- {
- fpath += this->GetAppBundleDirectory(config, contentOnly);
- }
- if(this->IsFrameworkOnApple())
- {
- fpath += this->GetFrameworkDirectory(config, contentOnly);
- }
- if(this->IsCFBundleOnApple())
- {
- fpath += this->GetCFBundleDirectory(config, contentOnly);
- }
- return fpath;
-}
-
-//----------------------------------------------------------------------------
-std::string cmTarget::GetMacContentDirectory(const std::string& config,
- bool implib) const
-{
- // Start with the output directory for the target.
- std::string fpath = this->GetDirectory(config, implib);
- fpath += "/";
- bool contentOnly = true;
- if(this->IsFrameworkOnApple())
- {
- // additional files with a framework go into the version specific
- // directory
- contentOnly = false;
- }
- fpath = this->BuildMacContentDirectory(fpath, config, contentOnly);
- return fpath;
-}
-
-//----------------------------------------------------------------------------
-cmTargetLinkInformationMap
-::cmTargetLinkInformationMap(cmTargetLinkInformationMap const& r): derived()
-{
- // Ideally cmTarget instances should never be copied. However until
- // we can make a sweep to remove that, this copy constructor avoids
- // allowing the resources (LinkInformation) from getting copied. In
- // the worst case this will lead to extra cmComputeLinkInformation
- // instances. We also enforce in debug mode that the map be emptied
- // when copied.
- static_cast<void>(r);
- assert(r.empty());
-}
-
-//----------------------------------------------------------------------------
-cmTargetLinkInformationMap::~cmTargetLinkInformationMap()
-{
- cmDeleteAll(*this);
-}
-
//----------------------------------------------------------------------------
cmTargetInternalPointer::cmTargetInternalPointer()
{
@@ -6791,10 +4846,10 @@ cmTargetInternalPointer
//----------------------------------------------------------------------------
cmTargetInternalPointer::~cmTargetInternalPointer()
{
- cmDeleteAll(this->Pointer->IncludeDirectoriesEntries);
- cmDeleteAll(this->Pointer->CompileOptionsEntries);
- cmDeleteAll(this->Pointer->CompileFeaturesEntries);
- cmDeleteAll(this->Pointer->CompileDefinitionsEntries);
+ cmDeleteAll(this->Pointer->IncludeDirectoriesItems);
+ cmDeleteAll(this->Pointer->CompileOptionsItems);
+ cmDeleteAll(this->Pointer->CompileFeaturesItems);
+ cmDeleteAll(this->Pointer->CompileDefinitionsItems);
cmDeleteAll(this->Pointer->SourceEntries);
delete this->Pointer;
}
diff --git a/Source/cmTarget.h b/Source/cmTarget.h
index f567d50..2007b40 100644
--- a/Source/cmTarget.h
+++ b/Source/cmTarget.h
@@ -16,6 +16,7 @@
#include "cmPropertyMap.h"
#include "cmPolicies.h"
#include "cmListFileCache.h"
+#include "cmLinkItem.h"
#include <cmsys/auto_ptr.hxx>
#if defined(CMAKE_BUILD_WITH_CMAKE)
@@ -52,41 +53,6 @@ class cmTarget;
class cmGeneratorTarget;
class cmTargetTraceDependencies;
-// Basic information about each link item.
-class cmLinkItem: public std::string
-{
- typedef std::string std_string;
-public:
- cmLinkItem(): std_string(), Target(0) {}
- cmLinkItem(const std_string& n,
- cmTarget const* t): std_string(n), Target(t) {}
- cmLinkItem(cmLinkItem const& r): std_string(r), Target(r.Target) {}
- cmTarget const* Target;
-};
-class cmLinkImplItem: public cmLinkItem
-{
-public:
- cmLinkImplItem(): cmLinkItem(), Backtrace(), FromGenex(false) {}
- cmLinkImplItem(std::string const& n,
- cmTarget const* t,
- cmListFileBacktrace const& bt,
- bool fromGenex):
- cmLinkItem(n, t), Backtrace(bt), FromGenex(fromGenex) {}
- cmLinkImplItem(cmLinkImplItem const& r):
- cmLinkItem(r), Backtrace(r.Backtrace), FromGenex(r.FromGenex) {}
- cmListFileBacktrace Backtrace;
- bool FromGenex;
-};
-
-struct cmTargetLinkInformationMap:
- public std::map<std::string, cmComputeLinkInformation*>
-{
- typedef std::map<std::string, cmComputeLinkInformation*> derived;
- cmTargetLinkInformationMap() {}
- cmTargetLinkInformationMap(cmTargetLinkInformationMap const& r);
- ~cmTargetLinkInformationMap();
-};
-
class cmTargetInternals;
class cmTargetInternalPointer
{
@@ -166,6 +132,8 @@ public:
void AddPostBuildCommand(cmCustomCommand const &cmd)
{this->PostBuildCommands.push_back(cmd);}
+ void Compute();
+
/**
* Get the list of the source files used by this target
*/
@@ -302,31 +270,7 @@ public:
cmTarget const* headTarget,
bool usage_requirements_only) const;
- std::vector<cmTarget const*> const&
- GetLinkImplementationClosure(const std::string& config) const;
-
- struct CompatibleInterfaces
- {
- std::set<std::string> PropsBool;
- std::set<std::string> PropsString;
- std::set<std::string> PropsNumberMax;
- std::set<std::string> PropsNumberMin;
- };
- CompatibleInterfaces const&
- GetCompatibleInterfaces(std::string const& config) const;
-
- /** The link implementation specifies the direct library
- dependencies needed by the object files of the target. */
- struct LinkImplementationLibraries
- {
- // Libraries linked directly in this configuration.
- std::vector<cmLinkImplItem> Libraries;
-
- // Libraries linked directly in other configurations.
- // Needed only for OLD behavior of CMP0003.
- std::vector<cmLinkItem> WrongConfigLibraries;
- };
- struct LinkImplementation: public LinkImplementationLibraries
+ struct LinkImplementation: public cmLinkImplementationLibraries
{
// Languages whose runtime libraries must be linked.
std::vector<std::string> Languages;
@@ -334,21 +278,9 @@ public:
LinkImplementation const*
GetLinkImplementation(const std::string& config) const;
- LinkImplementationLibraries const*
+ cmLinkImplementationLibraries const*
GetLinkImplementationLibraries(const std::string& config) const;
- /** Link information from the transitive closure of the link
- implementation and the interfaces of its dependencies. */
- struct LinkClosure
- {
- // The preferred linker language.
- std::string LinkerLanguage;
-
- // Languages whose runtime libraries must be linked.
- std::vector<std::string> Languages;
- };
- LinkClosure const* GetLinkClosure(const std::string& config) const;
-
cmTarget const* FindTargetToLink(std::string const& name) const;
/** Strip off leading and trailing whitespace from an item named in
@@ -368,12 +300,6 @@ public:
pdb output directory is given. */
std::string GetPDBDirectory(const std::string& config) const;
- /** Get the directory in which to place the target compiler .pdb file.
- If the configuration name is given then the generator will add its
- subdirectory for that configuration. Otherwise just the canonical
- compiler pdb output directory is given. */
- std::string GetCompilePDBDirectory(const std::string& config = "") const;
-
const char* ImportedGetLocation(const std::string& config) const;
/** Get the target major and minor version numbers interpreted from
@@ -387,33 +313,6 @@ public:
void
GetTargetVersion(bool soversion, int& major, int& minor, int& patch) const;
- ///! Return the preferred linker language for this target
- std::string GetLinkerLanguage(const std::string& config = "") const;
-
- /** Get the full name of the target according to the settings in its
- makefile. */
- std::string GetFullName(const std::string& config="",
- bool implib = false) const;
- void GetFullNameComponents(std::string& prefix,
- std::string& base, std::string& suffix,
- const std::string& config="",
- bool implib = false) const;
-
- /** Get the name of the pdb file for the target. */
- std::string GetPDBName(const std::string& config) const;
-
- /** Get the name of the compiler pdb file for the target. */
- std::string GetCompilePDBName(const std::string& config="") const;
-
- /** Get the path for the MSVC /Fd option for this target. */
- std::string GetCompilePDBPath(const std::string& config="") const;
-
- /** Whether this library has soname enabled and platform supports it. */
- bool HasSOName(const std::string& config) const;
-
- /** Get the soname of the target. Allowed only for a shared library. */
- std::string GetSOName(const std::string& config) const;
-
/** Whether this library has \@rpath and platform supports it. */
bool HasMacOSXRpathInstallNameDir(const std::string& config) const;
@@ -424,21 +323,6 @@ public:
no soname at all. */
bool IsImportedSharedLibWithoutSOName(const std::string& config) const;
- /** Get the names of the library needed to generate a build rule
- that takes into account shared library version numbers. This
- should be called only on a library target. */
- void GetLibraryNames(std::string& name, std::string& soName,
- std::string& realName, std::string& impName,
- std::string& pdbName, const std::string& config) const;
-
- /** Get the names of the executable needed to generate a build rule
- that takes into account executable version numbers. This should
- be called only on an executable target. */
- void GetExecutableNames(std::string& name, std::string& realName,
- std::string& impName,
- std::string& pdbName,
- const std::string& config) const;
-
/** Does this target have a GNU implib to convert to MS format? */
bool HasImplibGNUtoMS() const;
@@ -447,29 +331,9 @@ public:
bool GetImplibGNUtoMS(std::string const& gnuName, std::string& out,
const char* newExt = 0) const;
- /**
- * Compute whether this target must be relinked before installing.
- */
- bool NeedRelinkBeforeInstall(const std::string& config) const;
-
bool HaveBuildTreeRPATH(const std::string& config) const;
bool HaveInstallTreeRPATH() const;
- /** Return true if builtin chrpath will work for this target */
- bool IsChrpathUsed(const std::string& config) const;
-
- /** Return the install name directory for the target in the
- * build tree. For example: "\@rpath/", "\@loader_path/",
- * or "/full/path/to/library". */
- std::string GetInstallNameDirForBuildTree(const std::string& config) const;
-
- /** Return the install name directory for the target in the
- * install tree. For example: "\@rpath/" or "\@loader_path/". */
- std::string GetInstallNameDirForInstallTree() const;
-
- cmComputeLinkInformation*
- GetLinkInformation(const std::string& config) const;
-
// Get the properties
cmPropertyMap &GetProperties() const { return this->Properties; }
@@ -520,10 +384,6 @@ public:
/** Return whether this target is an executable Bundle on Apple. */
bool IsAppBundleOnApple() const;
- /** Return whether this target is an executable Bundle, a framework
- or CFBundle on Apple. */
- bool IsBundleOnApple() const;
-
/** Return the framework version string. Undefined if
IsFrameworkOnApple returns false. */
std::string GetFrameworkVersion() const;
@@ -538,25 +398,9 @@ public:
directory. */
bool UsesDefaultOutputDir(const std::string& config, bool implib) const;
- /** @return the mac content directory for this target. */
- std::string GetMacContentDirectory(const std::string& config,
- bool implib) const;
-
/** @return whether this target have a well defined output file name. */
bool HaveWellDefinedOutputFiles() const;
- /** @return the Mac framework directory without the base. */
- std::string GetFrameworkDirectory(const std::string& config,
- bool rootDir) const;
-
- /** @return the Mac CFBundle directory without the base */
- std::string GetCFBundleDirectory(const std::string& config,
- bool contentOnly) const;
-
- /** @return the Mac App directory without the base */
- std::string GetAppBundleDirectory(const std::string& config,
- bool contentOnly) const;
-
std::vector<std::string> GetIncludeDirectories(
const std::string& config,
const std::string& language) const;
@@ -574,47 +418,21 @@ public:
void GetCompileOptions(std::vector<std::string> &result,
const std::string& config,
const std::string& language) const;
- void GetAutoUicOptions(std::vector<std::string> &result,
- const std::string& config) const;
void GetCompileFeatures(std::vector<std::string> &features,
const std::string& config) const;
bool IsNullImpliedByLinkLibraries(const std::string &p) const;
- bool IsLinkInterfaceDependentBoolProperty(const std::string &p,
- const std::string& config) const;
- bool IsLinkInterfaceDependentStringProperty(const std::string &p,
- const std::string& config) const;
- bool IsLinkInterfaceDependentNumberMinProperty(const std::string &p,
- const std::string& config) const;
- bool IsLinkInterfaceDependentNumberMaxProperty(const std::string &p,
- const std::string& config) const;
-
- bool GetLinkInterfaceDependentBoolProperty(const std::string &p,
- const std::string& config) const;
-
- const char *GetLinkInterfaceDependentStringProperty(const std::string &p,
- const std::string& config) const;
- const char *GetLinkInterfaceDependentNumberMinProperty(const std::string &p,
- const std::string& config) const;
- const char *GetLinkInterfaceDependentNumberMaxProperty(const std::string &p,
- const std::string& config) const;
std::string GetDebugGeneratorExpressions(const std::string &value,
cmTarget::LinkLibraryType llt) const;
void AddSystemIncludeDirectories(const std::set<std::string> &incs);
- void AddSystemIncludeDirectories(const std::vector<std::string> &incs);
std::set<std::string> const & GetSystemIncludeDirectories() const
{ return this->SystemIncludeDirectories; }
bool LinkLanguagePropagatesToDependents() const
{ return this->TargetTypeValue == STATIC_LIBRARY; }
- void ReportPropertyOrigin(const std::string &p,
- const std::string &result,
- const std::string &report,
- const std::string &compatibilityType) const;
-
std::map<std::string, std::string> const&
GetMaxLanguageStandards() const
{
@@ -684,11 +502,6 @@ private:
const char* GetSuffixVariableInternal(bool implib) const;
const char* GetPrefixVariableInternal(bool implib) const;
- std::string GetFullNameInternal(const std::string& config,
- bool implib) const;
- void GetFullNameInternal(const std::string& config, bool implib,
- std::string& outPrefix, std::string& outBase,
- std::string& outSuffix) const;
// Use a makefile variable to set a default for the given property.
// If the variable is not defined use the given default instead.
@@ -698,19 +511,12 @@ private:
// Returns ARCHIVE, LIBRARY, or RUNTIME based on platform and type.
const char* GetOutputTargetType(bool implib) const;
- // Get the target base name.
- std::string GetOutputName(const std::string& config, bool implib) const;
-
std::string GetFullNameImported(const std::string& config,
bool implib) const;
std::string ImportedGetFullPath(const std::string& config,
bool implib) const;
- /** Append to @a base the mac content directory and return it. */
- std::string BuildMacContentDirectory(const std::string& base,
- const std::string& config,
- bool contentOnly) const;
void GetSourceFiles(std::vector<std::string> &files,
const std::string& config) const;
@@ -721,7 +527,6 @@ private:
std::set<std::string> Utilities;
mutable std::set<std::string> LinkImplicitNullProperties;
std::map<std::string, cmListFileBacktrace> UtilityBacktraces;
- mutable std::map<std::string, bool> DebugCompatiblePropertiesDone;
mutable std::map<std::string, std::string> MaxLanguageStandards;
cmPolicies::PolicyMap PolicyMap;
std::string Name;
@@ -768,27 +573,32 @@ private:
std::string& out) const;
// Cache import information from properties for each configuration.
- struct ImportInfo;
+ struct ImportInfo
+ {
+ ImportInfo(): NoSOName(false), Multiplicity(0) {}
+ bool NoSOName;
+ int Multiplicity;
+ std::string Location;
+ std::string SOName;
+ std::string ImportLibrary;
+ std::string Languages;
+ std::string Libraries;
+ std::string LibrariesProp;
+ std::string SharedDeps;
+ };
+
ImportInfo const* GetImportInfo(const std::string& config) const;
void ComputeImportInfo(std::string const& desired_config,
ImportInfo& info) const;
- // Cache target compile paths for each configuration.
- struct CompileInfo;
- CompileInfo const* GetCompileInfo(const std::string& config) const;
-
- mutable cmTargetLinkInformationMap LinkInformation;
- void CheckPropertyCompatibility(cmComputeLinkInformation *info,
- const std::string& config) const;
LinkInterface const*
GetImportLinkInterface(const std::string& config, cmTarget const* head,
bool usage_requirements_only) const;
- LinkImplementationLibraries const*
+ cmLinkImplementationLibraries const*
GetLinkImplementationLibrariesInternal(const std::string& config,
cmTarget const* head) const;
- void ComputeLinkClosure(const std::string& config, LinkClosure& lc) const;
void ExpandLinkItems(std::string const& prop, std::string const& value,
std::string const& config, cmTarget const* headTarget,
diff --git a/Source/cmTargetIncludeDirectoriesCommand.cxx b/Source/cmTargetIncludeDirectoriesCommand.cxx
index 7824c89..7dfe9ca 100644
--- a/Source/cmTargetIncludeDirectoriesCommand.cxx
+++ b/Source/cmTargetIncludeDirectoriesCommand.cxx
@@ -75,7 +75,23 @@ bool cmTargetIncludeDirectoriesCommand
tgt->InsertInclude(this->Join(content), lfbt, prepend);
if (system)
{
- tgt->AddSystemIncludeDirectories(content);
+ std::string prefix =
+ this->Makefile->GetCurrentSourceDirectory() + std::string("/");
+ std::set<std::string> sdirs;
+ for (std::vector<std::string>::const_iterator it = content.begin();
+ it != content.end(); ++it)
+ {
+ if (cmSystemTools::FileIsFullPath(it->c_str())
+ || cmGeneratorExpression::Find(*it) == 0)
+ {
+ sdirs.insert(*it);
+ }
+ else
+ {
+ sdirs.insert(prefix + *it);
+ }
+ }
+ tgt->AddSystemIncludeDirectories(sdirs);
}
return true;
}
@@ -91,7 +107,7 @@ void cmTargetIncludeDirectoriesCommand
if (system)
{
- std::string joined = cmJoin(content, ";");
+ std::string joined = this->Join(content);
tgt->AppendProperty("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES",
joined.c_str());
}
diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx
index 71785e9..80b8591 100644
--- a/Source/cmVisualStudio10TargetGenerator.cxx
+++ b/Source/cmVisualStudio10TargetGenerator.cxx
@@ -1627,7 +1627,7 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags(
this->GlobalGenerator->GetLanguageFromExtension
(sf.GetExtension().c_str());
std::string sourceLang = this->LocalGenerator->GetSourceFileLanguage(sf);
- const std::string& linkLanguage = this->Target->GetLinkerLanguage();
+ const std::string& linkLanguage = this->GeneratorTarget->GetLinkerLanguage();
bool needForceLang = false;
// source file does not match its extension language
if(lang != sourceLang)
@@ -1774,7 +1774,7 @@ void cmVisualStudio10TargetGenerator::WritePathAndIncrementalLinkOptions()
else
{
outDir = this->Target->GetDirectory(config->c_str()) + "/";
- targetNameFull = this->Target->GetFullName(config->c_str());
+ targetNameFull = this->GeneratorTarget->GetFullName(config->c_str());
}
this->ConvertToWindowsSlash(intermediateDir);
this->ConvertToWindowsSlash(outDir);
@@ -1888,7 +1888,7 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions(
std::string flags;
const std::string& linkLanguage =
- this->Target->GetLinkerLanguage(configName.c_str());
+ this->GeneratorTarget->GetLinkerLanguage(configName.c_str());
if(linkLanguage.empty())
{
cmSystemTools::Error
@@ -2026,7 +2026,8 @@ void cmVisualStudio10TargetGenerator::WriteClOptions(
}
// Specify the compiler program database file if configured.
- std::string pdb = this->Target->GetCompilePDBPath(configName.c_str());
+ std::string pdb =
+ this->GeneratorTarget->GetCompilePDBPath(configName.c_str());
if(!pdb.empty())
{
this->ConvertToWindowsSlash(pdb);
@@ -2370,7 +2371,7 @@ cmVisualStudio10TargetGenerator::ComputeLinkOptions(std::string const& config)
Options& linkOptions = *pOptions;
const std::string& linkLanguage =
- this->Target->GetLinkerLanguage(config.c_str());
+ this->GeneratorTarget->GetLinkerLanguage(config.c_str());
if(linkLanguage.empty())
{
cmSystemTools::Error
@@ -2438,7 +2439,7 @@ cmVisualStudio10TargetGenerator::ComputeLinkOptions(std::string const& config)
cmSystemTools::ExpandListArgument(libs, libVec);
cmComputeLinkInformation* pcli =
- this->Target->GetLinkInformation(config.c_str());
+ this->GeneratorTarget->GetLinkInformation(config.c_str());
if(!pcli)
{
cmSystemTools::Error
@@ -2471,13 +2472,14 @@ cmVisualStudio10TargetGenerator::ComputeLinkOptions(std::string const& config)
std::string targetNamePDB;
if(this->Target->GetType() == cmTarget::EXECUTABLE)
{
- this->Target->GetExecutableNames(targetName, targetNameFull,
+ this->GeneratorTarget->GetExecutableNames(targetName, targetNameFull,
targetNameImport, targetNamePDB,
config.c_str());
}
else
{
- this->Target->GetLibraryNames(targetName, targetNameSO, targetNameFull,
+ this->GeneratorTarget->GetLibraryNames(targetName, targetNameSO,
+ targetNameFull,
targetNameImport, targetNamePDB,
config.c_str());
}
diff --git a/Source/cmXCodeObject.cxx b/Source/cmXCodeObject.cxx
index e72d315..c59c360 100644
--- a/Source/cmXCodeObject.cxx
+++ b/Source/cmXCodeObject.cxx
@@ -243,7 +243,11 @@ void cmXCodeObject::PrintString(std::ostream& os,std::string String)
bool needQuote =
(String.empty() ||
String.find("//") != String.npos ||
- String.find_first_of(" <>+-*=@[](){},") != String.npos);
+ String.find_first_not_of(
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789"
+ "$_./") != String.npos);
const char* quote = needQuote? "\"" : "";
// Print the string, quoted and escaped as necessary.
diff --git a/Source/cmake.cxx b/Source/cmake.cxx
index 9d2c19e..dbbe07d 100644
--- a/Source/cmake.cxx
+++ b/Source/cmake.cxx
@@ -75,7 +75,9 @@
# include "cmGlobalWatcomWMakeGenerator.h"
#endif
#include "cmGlobalUnixMakefileGenerator3.h"
-#include "cmGlobalNinjaGenerator.h"
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+# include "cmGlobalNinjaGenerator.h"
+#endif
#include "cmExtraCodeLiteGenerator.h"
#if !defined(CMAKE_BOOT_MINGW)
@@ -1447,7 +1449,7 @@ int cmake::ActualConfigure()
}
}
- cmMakefile* mf=this->GlobalGenerator->GetLocalGenerators()[0]->GetMakefile();
+ cmMakefile* mf=this->GlobalGenerator->GetMakefiles()[0];
if (mf->IsOn("CTEST_USE_LAUNCHERS")
&& !this->State->GetGlobalProperty("RULE_LAUNCH_COMPILE"))
{
@@ -1607,7 +1609,11 @@ int cmake::Generate()
{
return -1;
}
- this->GlobalGenerator->DoGenerate();
+ if (!this->GlobalGenerator->Compute())
+ {
+ return -1;
+ }
+ this->GlobalGenerator->Generate();
if ( !this->GraphVizFile.empty() )
{
std::cout << "Generate graphviz: " << this->GraphVizFile << std::endl;
@@ -1696,8 +1702,10 @@ void cmake::AddDefaultGenerators()
#endif
this->Generators.push_back(
cmGlobalUnixMakefileGenerator3::NewFactory());
+#if defined(CMAKE_BUILD_WITH_CMAKE)
this->Generators.push_back(
cmGlobalNinjaGenerator::NewFactory());
+#endif
#if defined(CMAKE_USE_WMAKE)
this->Generators.push_back(
cmGlobalWatcomWMakeGenerator::NewFactory());
@@ -2576,6 +2584,25 @@ int cmake::Build(const std::string& dir,
}
std::string cachePath = dir;
cmSystemTools::ConvertToUnixSlashes(cachePath);
+ std::string cacheFile = cachePath;
+ cacheFile += "/CMakeCache.txt";
+ if(!cmSystemTools::FileExists(cacheFile.c_str()))
+ {
+ // search in parent directories for cache
+ std::string cmakeFiles = cachePath;
+ cmakeFiles += "/CMakeFiles";
+ if(cmSystemTools::FileExists(cmakeFiles.c_str()))
+ {
+ std::string cachePathFound =
+ cmSystemTools::FileExistsInParentDirectories(
+ "CMakeCache.txt", cachePath.c_str(), "/");
+ if(!cachePathFound.empty())
+ {
+ cachePath = cmSystemTools::GetFilenamePath(cachePathFound);
+ }
+ }
+ }
+
if(!this->LoadCache(cachePath))
{
std::cerr << "Error: could not load cache\n";
diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx
index 71f47f3..7bee0ea 100644
--- a/Source/cmcmd.cxx
+++ b/Source/cmcmd.cxx
@@ -1468,18 +1468,24 @@ bool cmcmd::RunCommand(const char* comment,
std::string output;
int retCode =0;
// use rc command to create .res file
- cmSystemTools::RunSingleCommand(command,
- &output, &output,
- &retCode, 0, cmSystemTools::OUTPUT_NONE);
+ bool res = cmSystemTools::RunSingleCommand(command,
+ &output, &output,
+ &retCode, 0,
+ cmSystemTools::OUTPUT_NONE);
// always print the output of the command, unless
// it is the dumb rc command banner, but if the command
// returned an error code then print the output anyway as
// the banner may be mixed with some other important information.
if(output.find("Resource Compiler Version") == output.npos
- || retCode !=0)
+ || !res || retCode)
{
std::cout << output;
}
+ if (!res)
+ {
+ std::cout << comment << " failed to run." << std::endl;
+ return false;
+ }
// if retCodeOut is requested then always return true
// and set the retCodeOut to retCode
if(retCodeOut)
@@ -1593,7 +1599,10 @@ int cmcmd::VisualStudioLinkIncremental(std::vector<std::string>& args,
mtCommand.push_back(tempManifest);
// now run mt.exe to create the final manifest file
int mtRet =0;
- cmcmd::RunCommand("MT", mtCommand, verbose, &mtRet);
+ if(!cmcmd::RunCommand("MT", mtCommand, verbose, &mtRet))
+ {
+ return -1;
+ }
// if mt returns 0, then the manifest was not changed and
// we do not need to do another link step
if(mtRet == 0)
diff --git a/Source/kwsys/CMakeLists.txt b/Source/kwsys/CMakeLists.txt
index 7eb678b..017d619 100644
--- a/Source/kwsys/CMakeLists.txt
+++ b/Source/kwsys/CMakeLists.txt
@@ -1237,7 +1237,7 @@ IF(KWSYS_STANDALONE OR CMake_SOURCE_DIR)
IF(NOT CYGWIN)
SET(KWSYS_TEST_PROCESS_7 7)
ENDIF()
- FOREACH(n 1 2 3 4 5 6 ${KWSYS_TEST_PROCESS_7})
+ FOREACH(n 1 2 3 4 5 6 ${KWSYS_TEST_PROCESS_7} 9 10)
ADD_TEST(kwsys.testProcess-${n} ${EXEC_DIR}/${KWSYS_NAMESPACE}TestProcess ${n})
SET_PROPERTY(TEST kwsys.testProcess-${n} PROPERTY LABELS ${KWSYS_LABELS_TEST})
SET_TESTS_PROPERTIES(kwsys.testProcess-${n} PROPERTIES TIMEOUT 120)
@@ -1270,6 +1270,10 @@ IF(KWSYS_STANDALONE OR CMake_SOURCE_DIR)
MESSAGE(STATUS "GET_TEST_PROPERTY returned: ${wfv}")
ENDIF()
+ # Set up ctest custom configuration file.
+ CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/CTestCustom.cmake.in
+ ${PROJECT_BINARY_DIR}/CTestCustom.cmake @ONLY)
+
# Suppress known consistent failures on buggy systems.
IF(KWSYS_TEST_BOGUS_FAILURES)
SET_TESTS_PROPERTIES(${KWSYS_TEST_BOGUS_FAILURES} PROPERTIES WILL_FAIL ON)
diff --git a/Source/kwsys/CTestCustom.cmake.in b/Source/kwsys/CTestCustom.cmake.in
new file mode 100644
index 0000000..d6f802e
--- /dev/null
+++ b/Source/kwsys/CTestCustom.cmake.in
@@ -0,0 +1,15 @@
+# kwsys.testProcess-10 involves sending SIGINT to a child process, which then
+# exits abnormally via a call to _exit(). (On Windows, a call to ExitProcess).
+# Naturally, this results in plenty of memory being "leaked" by this child
+# process - the memory check results are not meaningful in this case.
+#
+# kwsys.testProcess-9 also tests sending SIGINT to a child process. However,
+# normal operation of that test involves the child process timing out, and the
+# host process kills (SIGKILL) it as a result. Since it was SIGKILL'ed, the
+# resulting memory leaks are not logged by valgrind anyway. Therefore, we
+# don't have to exclude it.
+
+set(CTEST_CUSTOM_MEMCHECK_IGNORE
+ ${CTEST_CUSTOM_MEMCHECK_IGNORE}
+ kwsys.testProcess-10
+ )
diff --git a/Source/kwsys/EncodingC.c b/Source/kwsys/EncodingC.c
index ba2cec2..32b9bff 100644
--- a/Source/kwsys/EncodingC.c
+++ b/Source/kwsys/EncodingC.c
@@ -45,8 +45,11 @@ wchar_t* kwsysEncoding_DupToWide(const char* str)
if(length > 0)
{
ret = (wchar_t*)malloc((length)*sizeof(wchar_t));
- ret[0] = 0;
- kwsysEncoding_mbstowcs(ret, str, length);
+ if(ret)
+ {
+ ret[0] = 0;
+ kwsysEncoding_mbstowcs(ret, str, length);
+ }
}
return ret;
}
@@ -72,8 +75,11 @@ char* kwsysEncoding_DupToNarrow(const wchar_t* str)
if(length > 0)
{
ret = (char*)malloc(length);
- ret[0] = 0;
- kwsysEncoding_wcstombs(ret, str, length);
+ if(ret)
+ {
+ ret[0] = 0;
+ kwsysEncoding_wcstombs(ret, str, length);
+ }
}
return ret;
}
diff --git a/Source/kwsys/Process.h.in b/Source/kwsys/Process.h.in
index e35939f..c5ebc97 100644
--- a/Source/kwsys/Process.h.in
+++ b/Source/kwsys/Process.h.in
@@ -23,58 +23,60 @@
# define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT
#endif
#if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
-# define kwsysProcess kwsys_ns(Process)
-# define kwsysProcess_s kwsys_ns(Process_s)
-# define kwsysProcess_New kwsys_ns(Process_New)
-# define kwsysProcess_Delete kwsys_ns(Process_Delete)
-# define kwsysProcess_SetCommand kwsys_ns(Process_SetCommand)
-# define kwsysProcess_AddCommand kwsys_ns(Process_AddCommand)
-# define kwsysProcess_SetTimeout kwsys_ns(Process_SetTimeout)
-# define kwsysProcess_SetWorkingDirectory kwsys_ns(Process_SetWorkingDirectory)
-# define kwsysProcess_SetPipeFile kwsys_ns(Process_SetPipeFile)
-# define kwsysProcess_SetPipeNative kwsys_ns(Process_SetPipeNative)
-# define kwsysProcess_SetPipeShared kwsys_ns(Process_SetPipeShared)
-# define kwsysProcess_Option_Detach kwsys_ns(Process_Option_Detach)
-# define kwsysProcess_Option_HideWindow kwsys_ns(Process_Option_HideWindow)
-# define kwsysProcess_Option_MergeOutput kwsys_ns(Process_Option_MergeOutput)
-# define kwsysProcess_Option_Verbatim kwsys_ns(Process_Option_Verbatim)
-# define kwsysProcess_GetOption kwsys_ns(Process_GetOption)
-# define kwsysProcess_SetOption kwsys_ns(Process_SetOption)
-# define kwsysProcess_Option_e kwsys_ns(Process_Option_e)
-# define kwsysProcess_State_Starting kwsys_ns(Process_State_Starting)
-# define kwsysProcess_State_Error kwsys_ns(Process_State_Error)
-# define kwsysProcess_State_Exception kwsys_ns(Process_State_Exception)
-# define kwsysProcess_State_Executing kwsys_ns(Process_State_Executing)
-# define kwsysProcess_State_Exited kwsys_ns(Process_State_Exited)
-# define kwsysProcess_State_Expired kwsys_ns(Process_State_Expired)
-# define kwsysProcess_State_Killed kwsys_ns(Process_State_Killed)
-# define kwsysProcess_State_Disowned kwsys_ns(Process_State_Disowned)
-# define kwsysProcess_GetState kwsys_ns(Process_GetState)
-# define kwsysProcess_State_e kwsys_ns(Process_State_e)
-# define kwsysProcess_Exception_None kwsys_ns(Process_Exception_None)
-# define kwsysProcess_Exception_Fault kwsys_ns(Process_Exception_Fault)
-# define kwsysProcess_Exception_Illegal kwsys_ns(Process_Exception_Illegal)
-# define kwsysProcess_Exception_Interrupt kwsys_ns(Process_Exception_Interrupt)
-# define kwsysProcess_Exception_Numerical kwsys_ns(Process_Exception_Numerical)
-# define kwsysProcess_Exception_Other kwsys_ns(Process_Exception_Other)
-# define kwsysProcess_GetExitException kwsys_ns(Process_GetExitException)
-# define kwsysProcess_Exception_e kwsys_ns(Process_Exception_e)
-# define kwsysProcess_GetExitCode kwsys_ns(Process_GetExitCode)
-# define kwsysProcess_GetExitValue kwsys_ns(Process_GetExitValue)
-# define kwsysProcess_GetErrorString kwsys_ns(Process_GetErrorString)
-# define kwsysProcess_GetExceptionString kwsys_ns(Process_GetExceptionString)
-# define kwsysProcess_Execute kwsys_ns(Process_Execute)
-# define kwsysProcess_Disown kwsys_ns(Process_Disown)
-# define kwsysProcess_WaitForData kwsys_ns(Process_WaitForData)
-# define kwsysProcess_Pipes_e kwsys_ns(Process_Pipes_e)
-# define kwsysProcess_Pipe_None kwsys_ns(Process_Pipe_None)
-# define kwsysProcess_Pipe_STDIN kwsys_ns(Process_Pipe_STDIN)
-# define kwsysProcess_Pipe_STDOUT kwsys_ns(Process_Pipe_STDOUT)
-# define kwsysProcess_Pipe_STDERR kwsys_ns(Process_Pipe_STDERR)
-# define kwsysProcess_Pipe_Timeout kwsys_ns(Process_Pipe_Timeout)
-# define kwsysProcess_Pipe_Handle kwsys_ns(Process_Pipe_Handle)
-# define kwsysProcess_WaitForExit kwsys_ns(Process_WaitForExit)
-# define kwsysProcess_Kill kwsys_ns(Process_Kill)
+# define kwsysProcess kwsys_ns(Process)
+# define kwsysProcess_s kwsys_ns(Process_s)
+# define kwsysProcess_New kwsys_ns(Process_New)
+# define kwsysProcess_Delete kwsys_ns(Process_Delete)
+# define kwsysProcess_SetCommand kwsys_ns(Process_SetCommand)
+# define kwsysProcess_AddCommand kwsys_ns(Process_AddCommand)
+# define kwsysProcess_SetTimeout kwsys_ns(Process_SetTimeout)
+# define kwsysProcess_SetWorkingDirectory kwsys_ns(Process_SetWorkingDirectory)
+# define kwsysProcess_SetPipeFile kwsys_ns(Process_SetPipeFile)
+# define kwsysProcess_SetPipeNative kwsys_ns(Process_SetPipeNative)
+# define kwsysProcess_SetPipeShared kwsys_ns(Process_SetPipeShared)
+# define kwsysProcess_Option_Detach kwsys_ns(Process_Option_Detach)
+# define kwsysProcess_Option_HideWindow kwsys_ns(Process_Option_HideWindow)
+# define kwsysProcess_Option_MergeOutput kwsys_ns(Process_Option_MergeOutput)
+# define kwsysProcess_Option_Verbatim kwsys_ns(Process_Option_Verbatim)
+# define kwsysProcess_Option_CreateProcessGroup kwsys_ns(Process_Option_CreateProcessGroup)
+# define kwsysProcess_GetOption kwsys_ns(Process_GetOption)
+# define kwsysProcess_SetOption kwsys_ns(Process_SetOption)
+# define kwsysProcess_Option_e kwsys_ns(Process_Option_e)
+# define kwsysProcess_State_Starting kwsys_ns(Process_State_Starting)
+# define kwsysProcess_State_Error kwsys_ns(Process_State_Error)
+# define kwsysProcess_State_Exception kwsys_ns(Process_State_Exception)
+# define kwsysProcess_State_Executing kwsys_ns(Process_State_Executing)
+# define kwsysProcess_State_Exited kwsys_ns(Process_State_Exited)
+# define kwsysProcess_State_Expired kwsys_ns(Process_State_Expired)
+# define kwsysProcess_State_Killed kwsys_ns(Process_State_Killed)
+# define kwsysProcess_State_Disowned kwsys_ns(Process_State_Disowned)
+# define kwsysProcess_GetState kwsys_ns(Process_GetState)
+# define kwsysProcess_State_e kwsys_ns(Process_State_e)
+# define kwsysProcess_Exception_None kwsys_ns(Process_Exception_None)
+# define kwsysProcess_Exception_Fault kwsys_ns(Process_Exception_Fault)
+# define kwsysProcess_Exception_Illegal kwsys_ns(Process_Exception_Illegal)
+# define kwsysProcess_Exception_Interrupt kwsys_ns(Process_Exception_Interrupt)
+# define kwsysProcess_Exception_Numerical kwsys_ns(Process_Exception_Numerical)
+# define kwsysProcess_Exception_Other kwsys_ns(Process_Exception_Other)
+# define kwsysProcess_GetExitException kwsys_ns(Process_GetExitException)
+# define kwsysProcess_Exception_e kwsys_ns(Process_Exception_e)
+# define kwsysProcess_GetExitCode kwsys_ns(Process_GetExitCode)
+# define kwsysProcess_GetExitValue kwsys_ns(Process_GetExitValue)
+# define kwsysProcess_GetErrorString kwsys_ns(Process_GetErrorString)
+# define kwsysProcess_GetExceptionString kwsys_ns(Process_GetExceptionString)
+# define kwsysProcess_Execute kwsys_ns(Process_Execute)
+# define kwsysProcess_Disown kwsys_ns(Process_Disown)
+# define kwsysProcess_WaitForData kwsys_ns(Process_WaitForData)
+# define kwsysProcess_Pipes_e kwsys_ns(Process_Pipes_e)
+# define kwsysProcess_Pipe_None kwsys_ns(Process_Pipe_None)
+# define kwsysProcess_Pipe_STDIN kwsys_ns(Process_Pipe_STDIN)
+# define kwsysProcess_Pipe_STDOUT kwsys_ns(Process_Pipe_STDOUT)
+# define kwsysProcess_Pipe_STDERR kwsys_ns(Process_Pipe_STDERR)
+# define kwsysProcess_Pipe_Timeout kwsys_ns(Process_Pipe_Timeout)
+# define kwsysProcess_Pipe_Handle kwsys_ns(Process_Pipe_Handle)
+# define kwsysProcess_WaitForExit kwsys_ns(Process_WaitForExit)
+# define kwsysProcess_Interrupt kwsys_ns(Process_Interrupt)
+# define kwsysProcess_Kill kwsys_ns(Process_Kill)
#endif
#if defined(__cplusplus)
@@ -199,6 +201,15 @@ kwsysEXPORT void kwsysProcess_SetPipeNative(kwsysProcess* cp, int pipe,
* and ignore the rest of the arguments.
* 0 = No (default)
* 1 = Yes
+ *
+ * kwsysProcess_Option_CreateProcessGroup = Whether to place the process in a
+ * new process group. This is
+ * useful if you want to send Ctrl+C
+ * to the process. On UNIX, also
+ * places the process in a new
+ * session.
+ * 0 = No (default)
+ * 1 = Yes
*/
kwsysEXPORT int kwsysProcess_GetOption(kwsysProcess* cp, int optionId);
kwsysEXPORT void kwsysProcess_SetOption(kwsysProcess* cp, int optionId,
@@ -208,7 +219,8 @@ enum kwsysProcess_Option_e
kwsysProcess_Option_HideWindow,
kwsysProcess_Option_Detach,
kwsysProcess_Option_MergeOutput,
- kwsysProcess_Option_Verbatim
+ kwsysProcess_Option_Verbatim,
+ kwsysProcess_Option_CreateProcessGroup
};
/**
@@ -363,6 +375,17 @@ enum kwsysProcess_Pipes_e
kwsysEXPORT int kwsysProcess_WaitForExit(kwsysProcess* cp, double* timeout);
/**
+ * Interrupt the process group for the child process that is currently
+ * running by sending it the appropriate operating-system specific signal.
+ * The caller should call WaitForExit after this returns to wait for the
+ * child to terminate.
+ *
+ * WARNING: If you didn't specify kwsysProcess_Option_CreateProcessGroup,
+ * you will interrupt your own process group.
+ */
+kwsysEXPORT void kwsysProcess_Interrupt(kwsysProcess* cp);
+
+/**
* Forcefully terminate the child process that is currently running.
* The caller should call WaitForExit after this returns to wait for
* the child to terminate.
@@ -394,6 +417,7 @@ kwsysEXPORT void kwsysProcess_Kill(kwsysProcess* cp);
# undef kwsysProcess_Option_HideWindow
# undef kwsysProcess_Option_MergeOutput
# undef kwsysProcess_Option_Verbatim
+# undef kwsysProcess_Option_CreateProcessGroup
# undef kwsysProcess_GetOption
# undef kwsysProcess_SetOption
# undef kwsysProcess_Option_e
@@ -430,6 +454,7 @@ kwsysEXPORT void kwsysProcess_Kill(kwsysProcess* cp);
# undef kwsysProcess_Pipe_Timeout
# undef kwsysProcess_Pipe_Handle
# undef kwsysProcess_WaitForExit
+# undef kwsysProcess_Interrupt
# undef kwsysProcess_Kill
# endif
#endif
diff --git a/Source/kwsys/ProcessUNIX.c b/Source/kwsys/ProcessUNIX.c
index 0393a6d..6d9b109 100644
--- a/Source/kwsys/ProcessUNIX.c
+++ b/Source/kwsys/ProcessUNIX.c
@@ -88,7 +88,7 @@ typedef ssize_t kwsysProcess_ssize_t;
typedef int kwsysProcess_ssize_t;
#endif
-#if defined(__BEOS__) && !defined(__ZETA__)
+#if defined(__BEOS__) && !defined(__ZETA__)
/* BeOS 5 doesn't have usleep(), but it has snooze(), which is identical. */
# include <be/kernel/OS.h>
static inline void kwsysProcess_usleep(unsigned int msec)
@@ -151,6 +151,7 @@ typedef struct kwsysProcessCreateInformation_s
} kwsysProcessCreateInformation;
/*--------------------------------------------------------------------------*/
+static void kwsysProcessVolatileFree(volatile void* p);
static int kwsysProcessInitialize(kwsysProcess* cp);
static void kwsysProcessCleanup(kwsysProcess* cp, int error);
static void kwsysProcessCleanupDescriptor(int* pfd);
@@ -197,7 +198,7 @@ struct kwsysProcess_s
{
/* The command lines to execute. */
char*** Commands;
- int NumberOfCommands;
+ volatile int NumberOfCommands;
/* Descriptors for the read ends of the child's output pipes and
the signal pipe. */
@@ -213,8 +214,10 @@ struct kwsysProcess_s
/* Buffer for pipe data. */
char PipeBuffer[KWSYSPE_PIPE_BUFFER_SIZE];
- /* Process IDs returned by the calls to fork. */
- pid_t* ForkPIDs;
+ /* Process IDs returned by the calls to fork. Everything is volatile
+ because the signal handler accesses them. You must be very careful
+ when reaping PIDs or modifying this array to avoid race conditions. */
+ volatile pid_t* volatile ForkPIDs;
/* Flag for whether the children were terminated by a faild select. */
int SelectError;
@@ -237,6 +240,9 @@ struct kwsysProcess_s
/* Whether to merge stdout/stderr of the child. */
int MergeOutput;
+ /* Whether to create the process in a new process group. */
+ volatile sig_atomic_t CreateProcessGroup;
+
/* Time at which the child started. Negative for no timeout. */
kwsysProcessTime StartTime;
@@ -257,8 +263,9 @@ struct kwsysProcess_s
/* The number of children still executing. */
int CommandsLeft;
- /* The current status of the child process. */
- int State;
+ /* The current status of the child process. Must be atomic because
+ the signal handler checks this to avoid a race. */
+ volatile sig_atomic_t State;
/* The exceptional behavior that terminated the child process, if
* any. */
@@ -271,7 +278,7 @@ struct kwsysProcess_s
int ExitValue;
/* Whether the process was killed. */
- int Killed;
+ volatile sig_atomic_t Killed;
/* Buffer for error message in case of failure. */
char ErrorMessage[KWSYSPE_PIPE_BUFFER_SIZE+1];
@@ -649,6 +656,8 @@ int kwsysProcess_GetOption(kwsysProcess* cp, int optionId)
case kwsysProcess_Option_Detach: return cp->OptionDetach;
case kwsysProcess_Option_MergeOutput: return cp->MergeOutput;
case kwsysProcess_Option_Verbatim: return cp->Verbatim;
+ case kwsysProcess_Option_CreateProcessGroup:
+ return cp->CreateProcessGroup;
default: return 0;
}
}
@@ -666,6 +675,8 @@ void kwsysProcess_SetOption(kwsysProcess* cp, int optionId, int value)
case kwsysProcess_Option_Detach: cp->OptionDetach = value; break;
case kwsysProcess_Option_MergeOutput: cp->MergeOutput = value; break;
case kwsysProcess_Option_Verbatim: cp->Verbatim = value; break;
+ case kwsysProcess_Option_CreateProcessGroup:
+ cp->CreateProcessGroup = value; break;
default: break;
}
}
@@ -1490,6 +1501,45 @@ int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout)
}
/*--------------------------------------------------------------------------*/
+void kwsysProcess_Interrupt(kwsysProcess* cp)
+{
+ int i;
+ /* Make sure we are executing a process. */
+ if(!cp || cp->State != kwsysProcess_State_Executing || cp->TimeoutExpired ||
+ cp->Killed)
+ {
+ return;
+ }
+
+ /* Interrupt the children. */
+ if (cp->CreateProcessGroup)
+ {
+ if(cp->ForkPIDs)
+ {
+ for(i=0; i < cp->NumberOfCommands; ++i)
+ {
+ /* Make sure the PID is still valid. */
+ if(cp->ForkPIDs[i])
+ {
+ /* The user created a process group for this process. The group ID
+ is the process ID for the original process in the group. */
+ kill(-cp->ForkPIDs[i], SIGINT);
+ }
+ }
+ }
+ }
+ else
+ {
+ /* No process group was created. Kill our own process group.
+ NOTE: While one could argue that we could call kill(cp->ForkPIDs[i],
+ SIGINT) as a way to still interrupt the process even though it's not in
+ a special group, this is not an option on Windows. Therefore, we kill
+ the current process group for consistency with Windows. */
+ kill(0, SIGINT);
+ }
+}
+
+/*--------------------------------------------------------------------------*/
void kwsysProcess_Kill(kwsysProcess* cp)
{
int i;
@@ -1539,10 +1589,28 @@ void kwsysProcess_Kill(kwsysProcess* cp)
}
/*--------------------------------------------------------------------------*/
+/* Call the free() function with a pointer to volatile without causing
+ compiler warnings. */
+static void kwsysProcessVolatileFree(volatile void* p)
+{
+ /* clang has made it impossible to free memory that points to volatile
+ without first using special pragmas to disable a warning... */
+#if defined(__clang__)
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wcast-qual"
+#endif
+ free((void*)p); /* The cast will silence most compilers, but not clang. */
+#if defined(__clang__)
+# pragma clang diagnostic pop
+#endif
+}
+
+/*--------------------------------------------------------------------------*/
/* Initialize a process control structure for kwsysProcess_Execute. */
static int kwsysProcessInitialize(kwsysProcess* cp)
{
int i;
+ volatile pid_t* oldForkPIDs;
for(i=0; i < KWSYSPE_PIPE_COUNT; ++i)
{
cp->PipeReadEnds[i] = -1;
@@ -1571,16 +1639,21 @@ static int kwsysProcessInitialize(kwsysProcess* cp)
cp->ErrorMessage[0] = 0;
strcpy(cp->ExitExceptionString, "No exception");
- if(cp->ForkPIDs)
+ oldForkPIDs = cp->ForkPIDs;
+ cp->ForkPIDs = (volatile pid_t*)malloc(
+ sizeof(volatile pid_t)*(size_t)(cp->NumberOfCommands));
+ if(oldForkPIDs)
{
- free(cp->ForkPIDs);
+ kwsysProcessVolatileFree(oldForkPIDs);
}
- cp->ForkPIDs = (pid_t*)malloc(sizeof(pid_t)*(size_t)(cp->NumberOfCommands));
if(!cp->ForkPIDs)
{
return 0;
}
- memset(cp->ForkPIDs, 0, sizeof(pid_t)*(size_t)(cp->NumberOfCommands));
+ for(i=0; i < cp->NumberOfCommands; ++i)
+ {
+ cp->ForkPIDs[i] = 0; /* can't use memset due to volatile */
+ }
if(cp->CommandExitCodes)
{
@@ -1671,7 +1744,7 @@ static void kwsysProcessCleanup(kwsysProcess* cp, int error)
/* Free memory. */
if(cp->ForkPIDs)
{
- free(cp->ForkPIDs);
+ kwsysProcessVolatileFree(cp->ForkPIDs);
cp->ForkPIDs = 0;
}
if(cp->RealWorkingDirectory)
@@ -1758,15 +1831,49 @@ int decc$set_child_standard_streams(int fd1, int fd2, int fd3);
static int kwsysProcessCreate(kwsysProcess* cp, int prIndex,
kwsysProcessCreateInformation* si)
{
+ sigset_t mask, old_mask;
+ int pgidPipe[2];
+ char tmp;
+ ssize_t readRes;
+
/* Create the error reporting pipe. */
if(pipe(si->ErrorPipe) < 0)
{
return 0;
}
- /* Set close-on-exec flag on the error pipe's write end. */
- if(fcntl(si->ErrorPipe[1], F_SETFD, FD_CLOEXEC) < 0)
+ /* Create a pipe for detecting that the child process has created a process
+ group and session. */
+ if(pipe(pgidPipe) < 0)
{
+ kwsysProcessCleanupDescriptor(&si->ErrorPipe[0]);
+ kwsysProcessCleanupDescriptor(&si->ErrorPipe[1]);
+ return 0;
+ }
+
+ /* Set close-on-exec flag on the pipe's write end. */
+ if(fcntl(si->ErrorPipe[1], F_SETFD, FD_CLOEXEC) < 0 ||
+ fcntl(pgidPipe[1], F_SETFD, FD_CLOEXEC) < 0)
+ {
+ kwsysProcessCleanupDescriptor(&si->ErrorPipe[0]);
+ kwsysProcessCleanupDescriptor(&si->ErrorPipe[1]);
+ kwsysProcessCleanupDescriptor(&pgidPipe[0]);
+ kwsysProcessCleanupDescriptor(&pgidPipe[1]);
+ return 0;
+ }
+
+ /* Block SIGINT / SIGTERM while we start. The purpose is so that our signal
+ handler doesn't get called from the child process after the fork and
+ before the exec, and subsequently start kill()'ing PIDs from ForkPIDs. */
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGINT);
+ sigaddset(&mask, SIGTERM);
+ if(sigprocmask(SIG_BLOCK, &mask, &old_mask) < 0)
+ {
+ kwsysProcessCleanupDescriptor(&si->ErrorPipe[0]);
+ kwsysProcessCleanupDescriptor(&si->ErrorPipe[1]);
+ kwsysProcessCleanupDescriptor(&pgidPipe[0]);
+ kwsysProcessCleanupDescriptor(&pgidPipe[1]);
return 0;
}
@@ -1774,13 +1881,19 @@ static int kwsysProcessCreate(kwsysProcess* cp, int prIndex,
#if defined(__VMS)
/* VMS needs vfork and execvp to be in the same function because
they use setjmp/longjmp to run the child startup code in the
- parent! TODO: OptionDetach. */
+ parent! TODO: OptionDetach. Also
+ TODO: CreateProcessGroup. */
cp->ForkPIDs[prIndex] = vfork();
#else
cp->ForkPIDs[prIndex] = kwsysProcessFork(cp, si);
#endif
if(cp->ForkPIDs[prIndex] < 0)
{
+ sigprocmask(SIG_SETMASK, &old_mask, 0);
+ kwsysProcessCleanupDescriptor(&si->ErrorPipe[0]);
+ kwsysProcessCleanupDescriptor(&si->ErrorPipe[1]);
+ kwsysProcessCleanupDescriptor(&pgidPipe[0]);
+ kwsysProcessCleanupDescriptor(&pgidPipe[1]);
return 0;
}
@@ -1790,8 +1903,10 @@ static int kwsysProcessCreate(kwsysProcess* cp, int prIndex,
/* Specify standard pipes for child process. */
decc$set_child_standard_streams(si->StdIn, si->StdOut, si->StdErr);
#else
- /* Close the read end of the error reporting pipe. */
+ /* Close the read end of the error reporting / process group
+ setup pipe. */
close(si->ErrorPipe[0]);
+ close(pgidPipe[0]);
/* Setup the stdin, stdout, and stderr pipes. */
if(si->StdIn > 0)
@@ -1819,11 +1934,25 @@ static int kwsysProcessCreate(kwsysProcess* cp, int prIndex,
/* Restore all default signal handlers. */
kwsysProcessRestoreDefaultSignalHandlers();
+
+ /* Now that we have restored default signal handling and created the
+ process group, restore mask. */
+ sigprocmask(SIG_SETMASK, &old_mask, 0);
+
+ /* Create new process group. We use setsid instead of setpgid to avoid
+ the child getting hung up on signals like SIGTTOU. (In the real world,
+ this has been observed where "git svn" ends up calling the "resize"
+ program which opens /dev/tty. */
+ if(cp->CreateProcessGroup && setsid() < 0)
+ {
+ kwsysProcessChildErrorExit(si->ErrorPipe[1]);
+ }
#endif
/* Execute the real process. If successful, this does not return. */
execvp(cp->Commands[prIndex][0], cp->Commands[prIndex]);
/* TODO: What does VMS do if the child fails to start? */
+ /* TODO: On VMS, how do we put the process in a new group? */
/* Failure. Report error to parent and terminate. */
kwsysProcessChildErrorExit(si->ErrorPipe[1]);
@@ -1834,12 +1963,34 @@ static int kwsysProcessCreate(kwsysProcess* cp, int prIndex,
decc$set_child_standard_streams(0, 1, 2);
#endif
+ /* We are done with the error reporting pipe and process group setup pipe
+ write end. */
+ kwsysProcessCleanupDescriptor(&si->ErrorPipe[1]);
+ kwsysProcessCleanupDescriptor(&pgidPipe[1]);
+
+ /* Make sure the child is in the process group before we proceed. This
+ avoids race conditions with calls to the kill function that we make for
+ signalling process groups. */
+ while((readRes = read(pgidPipe[0], &tmp, 1)) > 0);
+ if(readRes < 0)
+ {
+ sigprocmask(SIG_SETMASK, &old_mask, 0);
+ kwsysProcessCleanupDescriptor(&si->ErrorPipe[0]);
+ kwsysProcessCleanupDescriptor(&pgidPipe[0]);
+ return 0;
+ }
+ kwsysProcessCleanupDescriptor(&pgidPipe[0]);
+
+ /* Unmask signals. */
+ if(sigprocmask(SIG_SETMASK, &old_mask, 0) < 0)
+ {
+ kwsysProcessCleanupDescriptor(&si->ErrorPipe[0]);
+ return 0;
+ }
+
/* A child has been created. */
++cp->CommandsLeft;
- /* We are done with the error reporting pipe write end. */
- kwsysProcessCleanupDescriptor(&si->ErrorPipe[1]);
-
/* Block until the child's exec call succeeds and closes the error
pipe or writes data to the pipe to report an error. */
{
@@ -1877,6 +2028,17 @@ static void kwsysProcessDestroy(kwsysProcess* cp)
/* A child process has terminated. Reap it if it is one handled by
this object. */
int i;
+ /* Temporarily disable signals that access ForkPIDs. We don't want them to
+ read a reaped PID, and writes to ForkPIDs are not atomic. */
+ sigset_t mask, old_mask;
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGINT);
+ sigaddset(&mask, SIGTERM);
+ if(sigprocmask(SIG_BLOCK, &mask, &old_mask) < 0)
+ {
+ return;
+ }
+
for(i=0; i < cp->NumberOfCommands; ++i)
{
if(cp->ForkPIDs[i])
@@ -1910,6 +2072,9 @@ static void kwsysProcessDestroy(kwsysProcess* cp)
}
}
}
+
+ /* Re-enable signals. */
+ sigprocmask(SIG_SETMASK, &old_mask, 0);
}
/*--------------------------------------------------------------------------*/
@@ -1938,7 +2103,7 @@ static int kwsysProcessSetupOutputPipeFile(int* p, const char* name)
/* Assign the replacement descriptor. */
*p = fout;
- return 1;
+ return 1;
}
/*--------------------------------------------------------------------------*/
@@ -2582,19 +2747,23 @@ typedef struct kwsysProcessInstances_s
} kwsysProcessInstances;
static kwsysProcessInstances kwsysProcesses;
-/* The old SIGCHLD handler. */
+/* The old SIGCHLD / SIGINT / SIGTERM handlers. */
static struct sigaction kwsysProcessesOldSigChldAction;
+static struct sigaction kwsysProcessesOldSigIntAction;
+static struct sigaction kwsysProcessesOldSigTermAction;
/*--------------------------------------------------------------------------*/
static void kwsysProcessesUpdate(kwsysProcessInstances* newProcesses)
{
- /* Block SIGCHLD while we update the set of pipes to check.
+ /* Block signals while we update the set of pipes to check.
TODO: sigprocmask is undefined for threaded apps. See
pthread_sigmask. */
sigset_t newset;
sigset_t oldset;
sigemptyset(&newset);
sigaddset(&newset, SIGCHLD);
+ sigaddset(&newset, SIGINT);
+ sigaddset(&newset, SIGTERM);
sigprocmask(SIG_BLOCK, &newset, &oldset);
/* Store the new set in that seen by the signal handler. */
@@ -2686,21 +2855,36 @@ static int kwsysProcessesAdd(kwsysProcess* cp)
{
/* Install our handler for SIGCHLD. Repeat call until it is not
interrupted. */
- struct sigaction newSigChldAction;
- memset(&newSigChldAction, 0, sizeof(struct sigaction));
+ struct sigaction newSigAction;
+ memset(&newSigAction, 0, sizeof(struct sigaction));
#if KWSYSPE_USE_SIGINFO
- newSigChldAction.sa_sigaction = kwsysProcessesSignalHandler;
- newSigChldAction.sa_flags = SA_NOCLDSTOP | SA_SIGINFO;
+ newSigAction.sa_sigaction = kwsysProcessesSignalHandler;
+ newSigAction.sa_flags = SA_NOCLDSTOP | SA_SIGINFO;
# ifdef SA_RESTART
- newSigChldAction.sa_flags |= SA_RESTART;
+ newSigAction.sa_flags |= SA_RESTART;
# endif
#else
- newSigChldAction.sa_handler = kwsysProcessesSignalHandler;
- newSigChldAction.sa_flags = SA_NOCLDSTOP;
+ newSigAction.sa_handler = kwsysProcessesSignalHandler;
+ newSigAction.sa_flags = SA_NOCLDSTOP;
#endif
- while((sigaction(SIGCHLD, &newSigChldAction,
+ sigemptyset(&newSigAction.sa_mask);
+ while((sigaction(SIGCHLD, &newSigAction,
&kwsysProcessesOldSigChldAction) < 0) &&
(errno == EINTR));
+
+ /* Install our handler for SIGINT / SIGTERM. Repeat call until
+ it is not interrupted. */
+ sigemptyset(&newSigAction.sa_mask);
+ sigaddset(&newSigAction.sa_mask, SIGTERM);
+ while((sigaction(SIGINT, &newSigAction,
+ &kwsysProcessesOldSigIntAction) < 0) &&
+ (errno == EINTR));
+
+ sigemptyset(&newSigAction.sa_mask);
+ sigaddset(&newSigAction.sa_mask, SIGINT);
+ while((sigaction(SIGTERM, &newSigAction,
+ &kwsysProcessesOldSigIntAction) < 0) &&
+ (errno == EINTR));
}
}
@@ -2734,10 +2918,14 @@ static void kwsysProcessesRemove(kwsysProcess* cp)
/* If this was the last process, disable the signal handler. */
if(newProcesses.Count == 0)
{
- /* Restore the SIGCHLD handler. Repeat call until it is not
+ /* Restore the signal handlers. Repeat call until it is not
interrupted. */
while((sigaction(SIGCHLD, &kwsysProcessesOldSigChldAction, 0) < 0) &&
(errno == EINTR));
+ while((sigaction(SIGINT, &kwsysProcessesOldSigIntAction, 0) < 0) &&
+ (errno == EINTR));
+ while((sigaction(SIGTERM, &kwsysProcessesOldSigTermAction, 0) < 0) &&
+ (errno == EINTR));
/* Free the table of process pointers since it is now empty.
This is safe because the signal handler has been removed. */
@@ -2763,39 +2951,108 @@ static void kwsysProcessesSignalHandler(int signum
#endif
)
{
- (void)signum;
+ int i, j, procStatus, old_errno = errno;
#if KWSYSPE_USE_SIGINFO
(void)info;
(void)ucontext;
#endif
/* Signal all process objects that a child has terminated. */
- {
- int i;
- for(i=0; i < kwsysProcesses.Count; ++i)
+ switch(signum)
{
- /* Set the pipe in a signalled state. */
- char buf = 1;
- kwsysProcess* cp = kwsysProcesses.Processes[i];
- kwsysProcess_ssize_t status=
- read(cp->PipeReadEnds[KWSYSPE_PIPE_SIGNAL], &buf, 1);
- (void)status;
- status=write(cp->SignalPipe, &buf, 1);
- (void)status;
+ case SIGCHLD:
+ for(i=0; i < kwsysProcesses.Count; ++i)
+ {
+ /* Set the pipe in a signalled state. */
+ char buf = 1;
+ kwsysProcess* cp = kwsysProcesses.Processes[i];
+ kwsysProcess_ssize_t pipeStatus=
+ read(cp->PipeReadEnds[KWSYSPE_PIPE_SIGNAL], &buf, 1);
+ (void)pipeStatus;
+ pipeStatus=write(cp->SignalPipe, &buf, 1);
+ (void)pipeStatus;
+ }
+ break;
+ case SIGINT:
+ case SIGTERM:
+ /* Signal child processes that are running in new process groups. */
+ for(i=0; i < kwsysProcesses.Count; ++i)
+ {
+ kwsysProcess* cp = kwsysProcesses.Processes[i];
+ /* Check Killed to avoid data race condition when killing.
+ Check State to avoid data race condition in kwsysProcessCleanup
+ when there is an error (it leaves a reaped PID). */
+ if(cp->CreateProcessGroup && !cp->Killed &&
+ cp->State != kwsysProcess_State_Error && cp->ForkPIDs)
+ {
+ for(j=0; j < cp->NumberOfCommands; ++j)
+ {
+ /* Make sure the PID is still valid. */
+ if(cp->ForkPIDs[j])
+ {
+ /* The user created a process group for this process. The group ID
+ is the process ID for the original process in the group. */
+ kill(-cp->ForkPIDs[j], SIGINT);
+ }
+ }
+ }
+ }
+
+ /* Wait for all processes to terminate. */
+ while(wait(&procStatus) >= 0 || errno != ECHILD)
+ {
+ }
+
+ /* Terminate the process, which is now in an inconsistent state
+ because we reaped all the PIDs that it may have been reaping
+ or may have reaped in the future. Reraise the signal so that
+ the proper exit code is returned. */
+ {
+ /* Install default signal handler. */
+ struct sigaction defSigAction;
+ sigset_t unblockSet;
+ memset(&defSigAction, 0, sizeof(defSigAction));
+ defSigAction.sa_handler = SIG_DFL;
+ sigemptyset(&defSigAction.sa_mask);
+ while((sigaction(signum, &defSigAction, 0) < 0) &&
+ (errno == EINTR));
+ /* Unmask the signal. */
+ sigemptyset(&unblockSet);
+ sigaddset(&unblockSet, signum);
+ sigprocmask(SIG_UNBLOCK, &unblockSet, 0);
+ /* Raise the signal again. */
+ raise(signum);
+ /* We shouldn't get here... but if we do... */
+ _exit(1);
+ }
+ /* break omitted to silence unreachable code clang compiler warning. */
}
- }
#if !KWSYSPE_USE_SIGINFO
- /* Re-Install our handler for SIGCHLD. Repeat call until it is not
- interrupted. */
+ /* Re-Install our handler. Repeat call until it is not interrupted. */
{
- struct sigaction newSigChldAction;
- memset(&newSigChldAction, 0, sizeof(struct sigaction));
+ struct sigaction newSigAction;
+ struct sigaction &oldSigAction;
+ memset(&newSigAction, 0, sizeof(struct sigaction));
newSigChldAction.sa_handler = kwsysProcessesSignalHandler;
newSigChldAction.sa_flags = SA_NOCLDSTOP;
- while((sigaction(SIGCHLD, &newSigChldAction,
- &kwsysProcessesOldSigChldAction) < 0) &&
+ sigemptyset(&newSigAction.sa_mask);
+ switch(signum)
+ {
+ case SIGCHLD: oldSigAction = &kwsysProcessesOldSigChldAction; break;
+ case SIGINT:
+ sigaddset(&newSigAction.sa_mask, SIGTERM);
+ oldSigAction = &kwsysProcessesOldSigIntAction; break;
+ case SIGTERM:
+ sigaddset(&newSigAction.sa_mask, SIGINT);
+ oldSigAction = &kwsysProcessesOldSigTermAction; break;
+ default: return 0;
+ }
+ while((sigaction(signum, &newSigAction,
+ oldSigAction) < 0) &&
(errno == EINTR));
}
#endif
+
+ errno = old_errno;
}
diff --git a/Source/kwsys/ProcessWin32.c b/Source/kwsys/ProcessWin32.c
index a7dd2ca..1f8749f 100644
--- a/Source/kwsys/ProcessWin32.c
+++ b/Source/kwsys/ProcessWin32.c
@@ -109,14 +109,15 @@ static DWORD WINAPI kwsysProcessPipeThreadWake(LPVOID ptd);
static void kwsysProcessPipeThreadWakePipe(kwsysProcess* cp,
kwsysProcessPipeData* td);
static int kwsysProcessInitialize(kwsysProcess* cp);
-static int kwsysProcessCreate(kwsysProcess* cp, int index,
- kwsysProcessCreateInformation* si);
+static DWORD kwsysProcessCreate(kwsysProcess* cp, int index,
+ kwsysProcessCreateInformation* si);
static void kwsysProcessDestroy(kwsysProcess* cp, int event);
-static int kwsysProcessSetupOutputPipeFile(PHANDLE handle, const char* name);
+static DWORD kwsysProcessSetupOutputPipeFile(PHANDLE handle,
+ const char* name);
static void kwsysProcessSetupSharedPipe(DWORD nStdHandle, PHANDLE handle);
static void kwsysProcessSetupPipeNative(HANDLE native, PHANDLE handle);
static void kwsysProcessCleanupHandle(PHANDLE h);
-static void kwsysProcessCleanup(kwsysProcess* cp, int error);
+static void kwsysProcessCleanup(kwsysProcess* cp, DWORD error);
static void kwsysProcessCleanErrorMessage(kwsysProcess* cp);
static int kwsysProcessGetTimeoutTime(kwsysProcess* cp, double* userTimeout,
kwsysProcessTime* timeoutTime);
@@ -133,6 +134,13 @@ static kwsysProcessTime kwsysProcessTimeSubtract(kwsysProcessTime in1, kwsysProc
static void kwsysProcessSetExitException(kwsysProcess* cp, int code);
static void kwsysProcessKillTree(int pid);
static void kwsysProcessDisablePipeThreads(kwsysProcess* cp);
+static int kwsysProcessesInitialize(void);
+static int kwsysTryEnterCreateProcessSection(void);
+static void kwsysLeaveCreateProcessSection(void);
+static int kwsysProcessesAdd(HANDLE hProcess, DWORD dwProcessId,
+ int newProcessGroup);
+static void kwsysProcessesRemove(HANDLE hProcess);
+static BOOL WINAPI kwsysCtrlHandler(DWORD dwCtrlType);
/*--------------------------------------------------------------------------*/
/* A structure containing synchronization data for each thread. */
@@ -222,6 +230,9 @@ struct kwsysProcess_s
/* Whether to merge stdout/stderr of the child. */
int MergeOutput;
+ /* Whether to create the process in a new process group. */
+ int CreateProcessGroup;
+
/* Mutex to protect the shared index used by threads to report data. */
HANDLE SharedIndexMutex;
@@ -321,6 +332,16 @@ kwsysProcess* kwsysProcess_New(void)
/* Windows version number data. */
OSVERSIONINFO osv;
+ /* Initialize list of processes before we get any farther. It's especially
+ important that the console Ctrl handler be added BEFORE starting the
+ first process. This prevents the risk of an orphaned process being
+ started by the main thread while the default Ctrl handler is in
+ progress. */
+ if(!kwsysProcessesInitialize())
+ {
+ return 0;
+ }
+
/* Allocate a process control structure. */
cp = (kwsysProcess*)malloc(sizeof(kwsysProcess));
if(!cp)
@@ -836,6 +857,8 @@ int kwsysProcess_GetOption(kwsysProcess* cp, int optionId)
case kwsysProcess_Option_HideWindow: return cp->HideWindow;
case kwsysProcess_Option_MergeOutput: return cp->MergeOutput;
case kwsysProcess_Option_Verbatim: return cp->Verbatim;
+ case kwsysProcess_Option_CreateProcessGroup:
+ return cp->CreateProcessGroup;
default: return 0;
}
}
@@ -854,6 +877,8 @@ void kwsysProcess_SetOption(kwsysProcess* cp, int optionId, int value)
case kwsysProcess_Option_HideWindow: cp->HideWindow = value; break;
case kwsysProcess_Option_MergeOutput: cp->MergeOutput = value; break;
case kwsysProcess_Option_Verbatim: cp->Verbatim = value; break;
+ case kwsysProcess_Option_CreateProcessGroup:
+ cp->CreateProcessGroup = value; break;
default: break;
}
}
@@ -945,7 +970,7 @@ void kwsysProcess_Execute(kwsysProcess* cp)
if(!GetCurrentDirectoryW(cp->RealWorkingDirectoryLength,
cp->RealWorkingDirectory))
{
- kwsysProcessCleanup(cp, 1);
+ kwsysProcessCleanup(cp, GetLastError());
return;
}
SetCurrentDirectoryW(cp->WorkingDirectory);
@@ -957,14 +982,16 @@ void kwsysProcess_Execute(kwsysProcess* cp)
{
/* Create a handle to read a file for stdin. */
wchar_t* wstdin = kwsysEncoding_DupToWide(cp->PipeFileSTDIN);
+ DWORD error;
cp->PipeChildStd[0] =
CreateFileW(wstdin, GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE,
0, OPEN_EXISTING, 0, 0);
+ error = GetLastError(); /* Check now in case free changes this. */
free(wstdin);
if(cp->PipeChildStd[0] == INVALID_HANDLE_VALUE)
{
- kwsysProcessCleanup(cp, 1);
+ kwsysProcessCleanup(cp, error);
return;
}
}
@@ -990,17 +1017,18 @@ void kwsysProcess_Execute(kwsysProcess* cp)
if(!CreatePipe(&cp->Pipe[KWSYSPE_PIPE_STDOUT].Read,
&cp->Pipe[KWSYSPE_PIPE_STDOUT].Write, 0, 0))
{
- kwsysProcessCleanup(cp, 1);
+ kwsysProcessCleanup(cp, GetLastError());
return;
}
if(cp->PipeFileSTDOUT)
{
/* Use a file for stdout. */
- if(!kwsysProcessSetupOutputPipeFile(&cp->PipeChildStd[1],
- cp->PipeFileSTDOUT))
+ DWORD error = kwsysProcessSetupOutputPipeFile(&cp->PipeChildStd[1],
+ cp->PipeFileSTDOUT);
+ if(error)
{
- kwsysProcessCleanup(cp, 1);
+ kwsysProcessCleanup(cp, error);
return;
}
}
@@ -1023,7 +1051,7 @@ void kwsysProcess_Execute(kwsysProcess* cp)
GetCurrentProcess(), &cp->PipeChildStd[1],
0, FALSE, DUPLICATE_SAME_ACCESS))
{
- kwsysProcessCleanup(cp, 1);
+ kwsysProcessCleanup(cp, GetLastError());
return;
}
}
@@ -1034,17 +1062,18 @@ void kwsysProcess_Execute(kwsysProcess* cp)
if(!CreatePipe(&cp->Pipe[KWSYSPE_PIPE_STDERR].Read,
&cp->Pipe[KWSYSPE_PIPE_STDERR].Write, 0, 0))
{
- kwsysProcessCleanup(cp, 1);
+ kwsysProcessCleanup(cp, GetLastError());
return;
}
if(cp->PipeFileSTDERR)
{
/* Use a file for stderr. */
- if(!kwsysProcessSetupOutputPipeFile(&cp->PipeChildStd[2],
- cp->PipeFileSTDERR))
+ DWORD error = kwsysProcessSetupOutputPipeFile(&cp->PipeChildStd[2],
+ cp->PipeFileSTDERR);
+ if(error)
{
- kwsysProcessCleanup(cp, 1);
+ kwsysProcessCleanup(cp, error);
return;
}
}
@@ -1067,7 +1096,7 @@ void kwsysProcess_Execute(kwsysProcess* cp)
GetCurrentProcess(), &cp->PipeChildStd[2],
0, FALSE, DUPLICATE_SAME_ACCESS))
{
- kwsysProcessCleanup(cp, 1);
+ kwsysProcessCleanup(cp, GetLastError());
return;
}
}
@@ -1106,11 +1135,12 @@ void kwsysProcess_Execute(kwsysProcess* cp)
HANDLE p[2] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE};
if (!CreatePipe(&p[0], &p[1], 0, 0))
{
+ DWORD error = GetLastError();
if (nextStdInput != cp->PipeChildStd[0])
{
kwsysProcessCleanupHandle(&nextStdInput);
}
- kwsysProcessCleanup(cp, 1);
+ kwsysProcessCleanup(cp, error);
return;
}
nextStdInput = p[0];
@@ -1119,7 +1149,7 @@ void kwsysProcess_Execute(kwsysProcess* cp)
si.hStdError = cp->MergeOutput? cp->PipeChildStd[1] : cp->PipeChildStd[2];
{
- int res = kwsysProcessCreate(cp, i, &si);
+ DWORD error = kwsysProcessCreate(cp, i, &si);
/* Close our copies of pipes used between children. */
if (si.hStdInput != cp->PipeChildStd[0])
@@ -1134,7 +1164,7 @@ void kwsysProcess_Execute(kwsysProcess* cp)
{
kwsysProcessCleanupHandle(&si.hStdError);
}
- if (res)
+ if (!error)
{
cp->ProcessEvents[i+1] = cp->ProcessInformation[i].hProcess;
}
@@ -1144,7 +1174,7 @@ void kwsysProcess_Execute(kwsysProcess* cp)
{
kwsysProcessCleanupHandle(&nextStdInput);
}
- kwsysProcessCleanup(cp, 1);
+ kwsysProcessCleanup(cp, error);
return;
}
}
@@ -1460,6 +1490,52 @@ int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout)
}
/*--------------------------------------------------------------------------*/
+void kwsysProcess_Interrupt(kwsysProcess* cp)
+{
+ int i;
+ /* Make sure we are executing a process. */
+ if(!cp || cp->State != kwsysProcess_State_Executing || cp->TimeoutExpired ||
+ cp->Killed)
+ {
+ KWSYSPE_DEBUG((stderr, "interrupt: child not executing\n"));
+ return;
+ }
+
+ /* Skip actually interrupting the child if it has already terminated. */
+ if(cp->Terminated)
+ {
+ KWSYSPE_DEBUG((stderr, "interrupt: child already terminated\n"));
+ return;
+ }
+
+ /* Interrupt the children. */
+ if (cp->CreateProcessGroup)
+ {
+ if(cp->ProcessInformation)
+ {
+ for(i=0; i < cp->NumberOfCommands; ++i)
+ {
+ /* Make sure the process handle isn't closed (e.g. from disowning). */
+ if(cp->ProcessInformation[i].hProcess)
+ {
+ /* The user created a process group for this process. The group ID
+ is the process ID for the original process in the group. Note
+ that we have to use Ctrl+Break: Ctrl+C is not allowed for process
+ groups. */
+ GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT,
+ cp->ProcessInformation[i].dwProcessId);
+ }
+ }
+ }
+ }
+ else
+ {
+ /* No process group was created. Kill our own process group... */
+ GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, 0);
+ }
+}
+
+/*--------------------------------------------------------------------------*/
void kwsysProcess_Kill(kwsysProcess* cp)
{
int i;
@@ -1487,7 +1563,8 @@ void kwsysProcess_Kill(kwsysProcess* cp)
for(i=0; i < cp->NumberOfCommands; ++i)
{
kwsysProcessKillTree(cp->ProcessInformation[i].dwProcessId);
- // close the handle if we kill it
+ /* Remove from global list of processes and close handles. */
+ kwsysProcessesRemove(cp->ProcessInformation[i].hProcess);
kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hThread);
kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hProcess);
}
@@ -1686,7 +1763,7 @@ int kwsysProcessInitialize(kwsysProcess* cp)
}
/*--------------------------------------------------------------------------*/
-static int kwsysProcessCreateChildHandle(PHANDLE out, HANDLE in, int isStdIn)
+static DWORD kwsysProcessCreateChildHandle(PHANDLE out, HANDLE in, int isStdIn)
{
DWORD flags;
@@ -1697,13 +1774,19 @@ static int kwsysProcessCreateChildHandle(PHANDLE out, HANDLE in, int isStdIn)
if (flags & HANDLE_FLAG_INHERIT)
{
*out = in;
- return 1;
+ return ERROR_SUCCESS;
}
/* Create an inherited copy of this handle. */
- return DuplicateHandle(GetCurrentProcess(), in,
- GetCurrentProcess(), out,
- 0, TRUE, DUPLICATE_SAME_ACCESS);
+ if (DuplicateHandle(GetCurrentProcess(), in, GetCurrentProcess(), out,
+ 0, TRUE, DUPLICATE_SAME_ACCESS))
+ {
+ return ERROR_SUCCESS;
+ }
+ else
+ {
+ return GetLastError();
+ }
}
else
{
@@ -1719,29 +1802,46 @@ static int kwsysProcessCreateChildHandle(PHANDLE out, HANDLE in, int isStdIn)
(GENERIC_WRITE | FILE_READ_ATTRIBUTES)),
FILE_SHARE_READ|FILE_SHARE_WRITE,
&sa, OPEN_EXISTING, 0, 0);
- return *out != INVALID_HANDLE_VALUE;
+ return (*out != INVALID_HANDLE_VALUE) ? ERROR_SUCCESS : GetLastError();
}
-
}
/*--------------------------------------------------------------------------*/
-int kwsysProcessCreate(kwsysProcess* cp, int index,
- kwsysProcessCreateInformation* si)
+DWORD kwsysProcessCreate(kwsysProcess* cp, int index,
+ kwsysProcessCreateInformation* si)
{
- int res =
+ DWORD creationFlags;
+ DWORD error = ERROR_SUCCESS;
+
+ /* Check if we are currently exiting. */
+ if (!kwsysTryEnterCreateProcessSection())
+ {
+ /* The Ctrl handler is currently working on exiting our process. Rather
+ than return an error code, which could cause incorrect conclusions to be
+ reached by the caller, we simply hang. (For example, a CMake try_run
+ configure step might cause the project to configure wrong.) */
+ Sleep(INFINITE);
+ }
- /* Create inherited copies the handles. */
- kwsysProcessCreateChildHandle(&si->StartupInfo.hStdInput,
- si->hStdInput, 1) &&
- kwsysProcessCreateChildHandle(&si->StartupInfo.hStdOutput,
- si->hStdOutput, 0) &&
- kwsysProcessCreateChildHandle(&si->StartupInfo.hStdError,
- si->hStdError, 0) &&
+ /* Create the child in a suspended state so we can wait until all
+ children have been created before running any one. */
+ creationFlags = CREATE_SUSPENDED;
+ if (cp->CreateProcessGroup)
+ {
+ creationFlags |= CREATE_NEW_PROCESS_GROUP;
+ }
- /* Create the child in a suspended state so we can wait until all
- children have been created before running any one. */
- CreateProcessW(0, cp->Commands[index], 0, 0, TRUE, CREATE_SUSPENDED, 0,
- 0, &si->StartupInfo, &cp->ProcessInformation[index]);
+ /* Create inherited copies of the handles. */
+ (error = kwsysProcessCreateChildHandle(&si->StartupInfo.hStdInput,
+ si->hStdInput, 1)) ||
+ (error = kwsysProcessCreateChildHandle(&si->StartupInfo.hStdOutput,
+ si->hStdOutput, 0)) ||
+ (error = kwsysProcessCreateChildHandle(&si->StartupInfo.hStdError,
+ si->hStdError, 0)) ||
+ /* Create the process. */
+ (!CreateProcessW(0, cp->Commands[index], 0, 0, TRUE, creationFlags, 0,
+ 0, &si->StartupInfo, &cp->ProcessInformation[index]) &&
+ (error = GetLastError()));
/* Close the inherited copies of the handles. */
if (si->StartupInfo.hStdInput != si->hStdInput)
@@ -1757,7 +1857,23 @@ int kwsysProcessCreate(kwsysProcess* cp, int index,
kwsysProcessCleanupHandle(&si->StartupInfo.hStdError);
}
- return res;
+ /* Add the process to the global list of processes. */
+ if (!error &&
+ !kwsysProcessesAdd(cp->ProcessInformation[index].hProcess,
+ cp->ProcessInformation[index].dwProcessId, cp->CreateProcessGroup))
+ {
+ /* This failed for some reason. Kill the suspended process. */
+ TerminateProcess(cp->ProcessInformation[index].hProcess, 1);
+ /* And clean up... */
+ kwsysProcessCleanupHandle(&cp->ProcessInformation[index].hProcess);
+ kwsysProcessCleanupHandle(&cp->ProcessInformation[index].hThread);
+ strcpy(cp->ErrorMessage, "kwsysProcessesAdd function failed");
+ error = ERROR_NOT_ENOUGH_MEMORY; /* Most likely reason. */
+ }
+
+ /* If the console Ctrl handler is waiting for us, this will release it... */
+ kwsysLeaveCreateProcessSection();
+ return error;
}
/*--------------------------------------------------------------------------*/
@@ -1779,6 +1895,9 @@ void kwsysProcessDestroy(kwsysProcess* cp, int event)
GetExitCodeProcess(cp->ProcessInformation[index].hProcess,
&cp->CommandExitCodes[index]);
+ /* Remove from global list of processes. */
+ kwsysProcessesRemove(cp->ProcessInformation[index].hProcess);
+
/* Close the process handle for the terminated process. */
kwsysProcessCleanupHandle(&cp->ProcessInformation[index].hProcess);
@@ -1813,13 +1932,14 @@ void kwsysProcessDestroy(kwsysProcess* cp, int event)
}
/*--------------------------------------------------------------------------*/
-int kwsysProcessSetupOutputPipeFile(PHANDLE phandle, const char* name)
+DWORD kwsysProcessSetupOutputPipeFile(PHANDLE phandle, const char* name)
{
HANDLE fout;
wchar_t* wname;
+ DWORD error;
if(!name)
{
- return 1;
+ return ERROR_INVALID_PARAMETER;
}
/* Close the existing handle. */
@@ -1829,15 +1949,16 @@ int kwsysProcessSetupOutputPipeFile(PHANDLE phandle, const char* name)
wname = kwsysEncoding_DupToWide(name);
fout = CreateFileW(wname, GENERIC_WRITE, FILE_SHARE_READ, 0,
CREATE_ALWAYS, 0, 0);
+ error = GetLastError();
free(wname);
if(fout == INVALID_HANDLE_VALUE)
{
- return 0;
+ return error;
}
/* Assign the replacement handle. */
*phandle = fout;
- return 1;
+ return ERROR_SUCCESS;
}
/*--------------------------------------------------------------------------*/
@@ -1876,7 +1997,7 @@ void kwsysProcessCleanupHandle(PHANDLE h)
/*--------------------------------------------------------------------------*/
/* Close all handles created by kwsysProcess_Execute. */
-void kwsysProcessCleanup(kwsysProcess* cp, int error)
+void kwsysProcessCleanup(kwsysProcess* cp, DWORD error)
{
int i;
/* If this is an error case, report the error. */
@@ -1886,21 +2007,27 @@ void kwsysProcessCleanup(kwsysProcess* cp, int error)
if(cp->ErrorMessage[0] == 0)
{
/* Format the error message. */
- DWORD original = GetLastError();
wchar_t err_msg[KWSYSPE_PIPE_BUFFER_SIZE];
DWORD length = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_IGNORE_INSERTS, 0, original,
+ FORMAT_MESSAGE_IGNORE_INSERTS, 0, error,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
err_msg, KWSYSPE_PIPE_BUFFER_SIZE, 0);
- WideCharToMultiByte(CP_UTF8, 0, err_msg, -1, cp->ErrorMessage,
- KWSYSPE_PIPE_BUFFER_SIZE, NULL, NULL);
if(length < 1)
{
/* FormatMessage failed. Use a default message. */
_snprintf(cp->ErrorMessage, KWSYSPE_PIPE_BUFFER_SIZE,
"Process execution failed with error 0x%X. "
"FormatMessage failed with error 0x%X",
- original, GetLastError());
+ error, GetLastError());
+ }
+ if(!WideCharToMultiByte(CP_UTF8, 0, err_msg, -1, cp->ErrorMessage,
+ KWSYSPE_PIPE_BUFFER_SIZE, NULL, NULL))
+ {
+ /* WideCharToMultiByte failed. Use a default message. */
+ _snprintf(cp->ErrorMessage, KWSYSPE_PIPE_BUFFER_SIZE,
+ "Process execution failed with error 0x%X. "
+ "WideCharToMultiByte failed with error 0x%X",
+ error, GetLastError());
}
}
@@ -1923,6 +2050,8 @@ void kwsysProcessCleanup(kwsysProcess* cp, int error)
}
for(i=0; i < cp->NumberOfCommands; ++i)
{
+ /* Remove from global list of processes and close handles. */
+ kwsysProcessesRemove(cp->ProcessInformation[i].hProcess);
kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hThread);
kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hProcess);
}
@@ -2659,3 +2788,230 @@ static void kwsysProcessDisablePipeThreads(kwsysProcess* cp)
ReleaseSemaphore(cp->Pipe[cp->CurrentIndex].Reader.Go, 1, 0);
}
}
+
+/*--------------------------------------------------------------------------*/
+/* Global set of executing processes for use by the Ctrl handler.
+ This global instance will be zero-initialized by the compiler.
+
+ Note that the console Ctrl handler runs on a background thread and so
+ everything it does must be thread safe. Here, we track the hProcess
+ HANDLEs directly instead of kwsysProcess instances, so that we don't have
+ to make kwsysProcess thread safe. */
+typedef struct kwsysProcessInstance_s
+{
+ HANDLE hProcess;
+ DWORD dwProcessId;
+ int NewProcessGroup; /* Whether the process was created in a new group. */
+} kwsysProcessInstance;
+
+typedef struct kwsysProcessInstances_s
+{
+ /* Whether we have initialized key fields below, like critical sections. */
+ int Initialized;
+
+ /* Ctrl handler runs on a different thread, so we must sync access. */
+ CRITICAL_SECTION Lock;
+
+ int Exiting;
+ size_t Count;
+ size_t Size;
+ kwsysProcessInstance* Processes;
+} kwsysProcessInstances;
+static kwsysProcessInstances kwsysProcesses;
+
+/*--------------------------------------------------------------------------*/
+/* Initialize critial section and set up console Ctrl handler. You MUST call
+ this before using any other kwsysProcesses* functions below. */
+static int kwsysProcessesInitialize(void)
+{
+ /* Initialize everything if not done already. */
+ if(!kwsysProcesses.Initialized)
+ {
+ InitializeCriticalSection(&kwsysProcesses.Lock);
+
+ /* Set up console ctrl handler. */
+ if(!SetConsoleCtrlHandler(kwsysCtrlHandler, TRUE))
+ {
+ return 0;
+ }
+
+ kwsysProcesses.Initialized = 1;
+ }
+ return 1;
+}
+
+/*--------------------------------------------------------------------------*/
+/* The Ctrl handler waits on the global list of processes. To prevent an
+ orphaned process, do not create a new process if the Ctrl handler is
+ already running. Do so by using this function to check if it is ok to
+ create a process. */
+static int kwsysTryEnterCreateProcessSection(void)
+{
+ /* Enter main critical section; this means creating a process and the Ctrl
+ handler are mutually exclusive. */
+ EnterCriticalSection(&kwsysProcesses.Lock);
+ /* Indicate to the caller if they can create a process. */
+ if(kwsysProcesses.Exiting)
+ {
+ LeaveCriticalSection(&kwsysProcesses.Lock);
+ return 0;
+ }
+ else
+ {
+ return 1;
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+/* Matching function on successful kwsysTryEnterCreateProcessSection return.
+ Make sure you called kwsysProcessesAdd if applicable before calling this.*/
+static void kwsysLeaveCreateProcessSection(void)
+{
+ LeaveCriticalSection(&kwsysProcesses.Lock);
+}
+
+/*--------------------------------------------------------------------------*/
+/* Add new process to global process list. The Ctrl handler will wait for
+ the process to exit before it returns. Do not close the process handle
+ until after calling kwsysProcessesRemove. The newProcessGroup parameter
+ must be set if the process was created with CREATE_NEW_PROCESS_GROUP. */
+static int kwsysProcessesAdd(HANDLE hProcess, DWORD dwProcessid,
+ int newProcessGroup)
+{
+ if(!kwsysProcessesInitialize() || !hProcess ||
+ hProcess == INVALID_HANDLE_VALUE)
+ {
+ return 0;
+ }
+
+ /* Enter the critical section. */
+ EnterCriticalSection(&kwsysProcesses.Lock);
+
+ /* Make sure there is enough space for the new process handle. */
+ if(kwsysProcesses.Count == kwsysProcesses.Size)
+ {
+ size_t newSize;
+ kwsysProcessInstance *newArray;
+ /* Start with enough space for a small number of process handles
+ and double the size each time more is needed. */
+ newSize = kwsysProcesses.Size? kwsysProcesses.Size*2 : 4;
+
+ /* Try allocating the new block of memory. */
+ if(newArray = (kwsysProcessInstance*)malloc(
+ newSize*sizeof(kwsysProcessInstance)))
+ {
+ /* Copy the old process handles to the new memory. */
+ if(kwsysProcesses.Count > 0)
+ {
+ memcpy(newArray, kwsysProcesses.Processes,
+ kwsysProcesses.Count * sizeof(kwsysProcessInstance));
+ }
+ }
+ else
+ {
+ /* Failed to allocate memory for the new process handle set. */
+ LeaveCriticalSection(&kwsysProcesses.Lock);
+ return 0;
+ }
+
+ /* Free original array. */
+ free(kwsysProcesses.Processes);
+
+ /* Update original structure with new allocation. */
+ kwsysProcesses.Size = newSize;
+ kwsysProcesses.Processes = newArray;
+ }
+
+ /* Append the new process information to the set. */
+ kwsysProcesses.Processes[kwsysProcesses.Count].hProcess = hProcess;
+ kwsysProcesses.Processes[kwsysProcesses.Count].dwProcessId = dwProcessid;
+ kwsysProcesses.Processes[kwsysProcesses.Count++].NewProcessGroup =
+ newProcessGroup;
+
+ /* Leave critical section and return success. */
+ LeaveCriticalSection(&kwsysProcesses.Lock);
+
+ return 1;
+}
+
+/*--------------------------------------------------------------------------*/
+/* Removes process to global process list. */
+static void kwsysProcessesRemove(HANDLE hProcess)
+{
+ size_t i;
+
+ if (!hProcess || hProcess == INVALID_HANDLE_VALUE)
+ {
+ return;
+ }
+
+ EnterCriticalSection(&kwsysProcesses.Lock);
+
+ /* Find the given process in the set. */
+ for(i=0; i < kwsysProcesses.Count; ++i)
+ {
+ if(kwsysProcesses.Processes[i].hProcess == hProcess)
+ {
+ break;
+ }
+ }
+ if(i < kwsysProcesses.Count)
+ {
+ /* Found it! Remove the process from the set. */
+ --kwsysProcesses.Count;
+ for(; i < kwsysProcesses.Count; ++i)
+ {
+ kwsysProcesses.Processes[i] = kwsysProcesses.Processes[i+1];
+ }
+
+ /* If this was the last process, free the array. */
+ if(kwsysProcesses.Count == 0)
+ {
+ kwsysProcesses.Size = 0;
+ free(kwsysProcesses.Processes);
+ kwsysProcesses.Processes = 0;
+ }
+ }
+
+ LeaveCriticalSection(&kwsysProcesses.Lock);
+}
+
+/*--------------------------------------------------------------------------*/
+static BOOL WINAPI kwsysCtrlHandler(DWORD dwCtrlType)
+{
+ size_t i;
+ (void)dwCtrlType;
+ /* Enter critical section. */
+ EnterCriticalSection(&kwsysProcesses.Lock);
+
+ /* Set flag indicating that we are exiting. */
+ kwsysProcesses.Exiting = 1;
+
+ /* If some of our processes were created in a new process group, we must
+ manually interrupt them. They won't otherwise receive a Ctrl+C/Break. */
+ for(i=0; i < kwsysProcesses.Count; ++i)
+ {
+ if(kwsysProcesses.Processes[i].NewProcessGroup)
+ {
+ DWORD groupId = kwsysProcesses.Processes[i].dwProcessId;
+ if(groupId)
+ {
+ GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, groupId);
+ }
+ }
+ }
+
+ /* Wait for each child process to exit. This is the key step that prevents
+ us from leaving several orphaned children processes running in the
+ background when the user presses Ctrl+C. */
+ for(i=0; i < kwsysProcesses.Count; ++i)
+ {
+ WaitForSingleObject(kwsysProcesses.Processes[i].hProcess, INFINITE);
+ }
+
+ /* Leave critical section. */
+ LeaveCriticalSection(&kwsysProcesses.Lock);
+
+ /* Continue on to default Ctrl handler (which calls ExitProcess). */
+ return FALSE;
+}
diff --git a/Source/kwsys/SystemTools.cxx b/Source/kwsys/SystemTools.cxx
index 3452259..0714344 100644
--- a/Source/kwsys/SystemTools.cxx
+++ b/Source/kwsys/SystemTools.cxx
@@ -3198,8 +3198,16 @@ bool SystemTools::FileIsDirectory(const kwsys_stl::string& inName)
bool SystemTools::FileIsSymlink(const kwsys_stl::string& name)
{
#if defined( _WIN32 )
- (void)name;
- return false;
+ DWORD attr = GetFileAttributesW(
+ SystemTools::ConvertToWindowsExtendedPath(name).c_str());
+ if (attr != INVALID_FILE_ATTRIBUTES)
+ {
+ return (attr & FILE_ATTRIBUTE_REPARSE_POINT) != 0;
+ }
+ else
+ {
+ return false;
+ }
#else
struct stat fs;
if(lstat(name.c_str(), &fs) == 0)
@@ -4230,6 +4238,11 @@ SystemTools::DetectFileType(const char *filename,
return SystemTools::FileTypeUnknown;
}
+ if (SystemTools::FileIsDirectory(filename))
+ {
+ return SystemTools::FileTypeUnknown;
+ }
+
FILE *fp = Fopen(filename, "rb");
if (!fp)
{
@@ -4243,6 +4256,7 @@ SystemTools::DetectFileType(const char *filename,
fclose(fp);
if (read_length == 0)
{
+ delete [] buffer;
return SystemTools::FileTypeUnknown;
}
diff --git a/Source/kwsys/testProcess.c b/Source/kwsys/testProcess.c
index 47c3fb0..d0e20c1 100644
--- a/Source/kwsys/testProcess.c
+++ b/Source/kwsys/testProcess.c
@@ -29,26 +29,48 @@
# include <windows.h>
#else
# include <unistd.h>
+# include <signal.h>
#endif
#if defined(__BORLANDC__)
# pragma warn -8060 /* possibly incorrect assignment */
#endif
+/* Platform-specific sleep functions. */
+
#if defined(__BEOS__) && !defined(__ZETA__)
/* BeOS 5 doesn't have usleep(), but it has snooze(), which is identical. */
# include <be/kernel/OS.h>
-static inline void testProcess_usleep(unsigned int msec)
+static inline void testProcess_usleep(unsigned int usec)
+{
+ snooze(usec);
+}
+#elif defined(_WIN32)
+/* Windows can only sleep in millisecond intervals. */
+static void testProcess_usleep(unsigned int usec)
{
- snooze(msec);
+ Sleep(usec / 1000);
}
#else
# define testProcess_usleep usleep
#endif
+#if defined(_WIN32)
+static void testProcess_sleep(unsigned int sec)
+{
+ Sleep(sec*1000);
+}
+#else
+static void testProcess_sleep(unsigned int sec)
+{
+ sleep(sec);
+}
+#endif
+
int runChild(const char* cmd[], int state, int exception, int value,
int share, int output, int delay, double timeout, int poll,
- int repeat, int disown);
+ int repeat, int disown, int createNewGroup,
+ unsigned int interruptDelay);
static int test1(int argc, const char* argv[])
{
@@ -73,11 +95,7 @@ static int test3(int argc, const char* argv[])
fprintf(stderr, "Output before sleep on stderr from timeout test.\n");
fflush(stdout);
fflush(stderr);
-#if defined(_WIN32)
- Sleep(15000);
-#else
- sleep(15);
-#endif
+ testProcess_sleep(15);
fprintf(stdout, "Output after sleep on stdout from timeout test.\n");
fprintf(stderr, "Output after sleep on stderr from timeout test.\n");
return 0;
@@ -102,7 +120,7 @@ static int test4(int argc, const char* argv[])
#endif
(void)argc; (void)argv;
fprintf(stdout, "Output before crash on stdout from crash test.\n");
- fprintf(stderr, "Output before crash on stderr from crash test.\n");
+ fprintf(stderr, "Output before crash on stderr from crash test.\n");
fflush(stdout);
fflush(stderr);
assert(invalidAddress); /* Quiet Clang scan-build. */
@@ -127,7 +145,7 @@ static int test5(int argc, const char* argv[])
fflush(stdout);
fflush(stderr);
r = runChild(cmd, kwsysProcess_State_Exception,
- kwsysProcess_Exception_Fault, 1, 1, 1, 0, 15, 0, 1, 0);
+ kwsysProcess_Exception_Fault, 1, 1, 1, 0, 15, 0, 1, 0, 0, 0);
fprintf(stdout, "Output on stdout after recursive test.\n");
fprintf(stderr, "Output on stderr after recursive test.\n");
fflush(stdout);
@@ -168,11 +186,7 @@ static int test7(int argc, const char* argv[])
fflush(stdout);
fflush(stderr);
/* Sleep for 1 second. */
-#if defined(_WIN32)
- Sleep(1000);
-#else
- sleep(1);
-#endif
+ testProcess_sleep(1);
fprintf(stdout, "Output on stdout after sleep.\n");
fprintf(stderr, "Output on stderr after sleep.\n");
fflush(stdout);
@@ -196,7 +210,7 @@ static int test8(int argc, const char* argv[])
fflush(stdout);
fflush(stderr);
r = runChild(cmd, kwsysProcess_State_Disowned, kwsysProcess_Exception_None,
- 1, 1, 1, 0, 10, 0, 1, 1);
+ 1, 1, 1, 0, 10, 0, 1, 1, 0, 0);
fprintf(stdout, "Output on stdout after grandchild test.\n");
fprintf(stderr, "Output on stderr after grandchild test.\n");
fflush(stdout);
@@ -217,18 +231,137 @@ static int test8_grandchild(int argc, const char* argv[])
implemented. */
fclose(stdout);
fclose(stderr);
+ testProcess_sleep(15);
+ return 0;
+}
+
+static int test9(int argc, const char* argv[])
+{
+ /* Test Ctrl+C behavior: the root test program will send a Ctrl+C to this
+ process. Here, we start a child process that sleeps for a long time
+ while ignoring signals. The test is successful if this process waits
+ for the child to return before exiting from the Ctrl+C handler.
+
+ WARNING: This test will falsely pass if the share parameter of runChild
+ was set to 0 when invoking the test9 process. */
+ int r;
+ const char* cmd[4];
+ (void)argc;
+ cmd[0] = argv[0];
+ cmd[1] = "run";
+ cmd[2] = "109";
+ cmd[3] = 0;
+ fprintf(stdout, "Output on stdout before grandchild test.\n");
+ fprintf(stderr, "Output on stderr before grandchild test.\n");
+ fflush(stdout);
+ fflush(stderr);
+ r = runChild(cmd, kwsysProcess_State_Exited,
+ kwsysProcess_Exception_None,
+ 0, 1, 1, 0, 30, 0, 1, 0, 0, 0);
+ /* This sleep will avoid a race condition between this function exiting
+ normally and our Ctrl+C handler exiting abnormally after the process
+ exits. */
+ testProcess_sleep(1);
+ fprintf(stdout, "Output on stdout after grandchild test.\n");
+ fprintf(stderr, "Output on stderr after grandchild test.\n");
+ fflush(stdout);
+ fflush(stderr);
+ return r;
+}
+
#if defined(_WIN32)
- Sleep(15000);
+static BOOL WINAPI test9_grandchild_handler(DWORD dwCtrlType)
+{
+ /* Ignore all Ctrl+C/Break signals. We must use an actual handler function
+ instead of using SetConsoleCtrlHandler(NULL, TRUE) so that we can also
+ ignore Ctrl+Break in addition to Ctrl+C. */
+ (void)dwCtrlType;
+ return TRUE;
+}
+#endif
+
+static int test9_grandchild(int argc, const char* argv[])
+{
+ /* The grandchild just sleeps for a few seconds while ignoring signals. */
+ (void)argc; (void)argv;
+#if defined(_WIN32)
+ if(!SetConsoleCtrlHandler(test9_grandchild_handler, TRUE))
+ {
+ return 1;
+ }
#else
- sleep(15);
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_IGN;
+ sigemptyset(&sa.sa_mask);
+ if(sigaction(SIGINT, &sa, 0) < 0)
+ {
+ return 1;
+ }
#endif
+ fprintf(stdout, "Output on stdout from grandchild before sleep.\n");
+ fprintf(stderr, "Output on stderr from grandchild before sleep.\n");
+ fflush(stdout);
+ fflush(stderr);
+ /* Sleep for 9 seconds. */
+ testProcess_sleep(9);
+ fprintf(stdout, "Output on stdout from grandchild after sleep.\n");
+ fprintf(stderr, "Output on stderr from grandchild after sleep.\n");
+ fflush(stdout);
+ fflush(stderr);
+ return 0;
+}
+
+static int test10(int argc, const char* argv[])
+{
+ /* Test Ctrl+C behavior: the root test program will send a Ctrl+C to this
+ process. Here, we start a child process that sleeps for a long time and
+ processes signals normally. However, this grandchild is created in a new
+ process group - ensuring that Ctrl+C we receive is sent to our process
+ groups. We make sure it exits anyway. */
+ int r;
+ const char* cmd[4];
+ (void)argc;
+ cmd[0] = argv[0];
+ cmd[1] = "run";
+ cmd[2] = "110";
+ cmd[3] = 0;
+ fprintf(stdout, "Output on stdout before grandchild test.\n");
+ fprintf(stderr, "Output on stderr before grandchild test.\n");
+ fflush(stdout);
+ fflush(stderr);
+ r = runChild(cmd, kwsysProcess_State_Exception,
+ kwsysProcess_Exception_Interrupt,
+ 0, 1, 1, 0, 30, 0, 1, 0, 1, 0);
+ fprintf(stdout, "Output on stdout after grandchild test.\n");
+ fprintf(stderr, "Output on stderr after grandchild test.\n");
+ fflush(stdout);
+ fflush(stderr);
+ return r;
+}
+
+static int test10_grandchild(int argc, const char* argv[])
+{
+ /* The grandchild just sleeps for a few seconds and handles signals. */
+ (void)argc; (void)argv;
+ fprintf(stdout, "Output on stdout from grandchild before sleep.\n");
+ fprintf(stderr, "Output on stderr from grandchild before sleep.\n");
+ fflush(stdout);
+ fflush(stderr);
+ /* Sleep for 6 seconds. */
+ testProcess_sleep(6);
+ fprintf(stdout, "Output on stdout from grandchild after sleep.\n");
+ fprintf(stderr, "Output on stderr from grandchild after sleep.\n");
+ fflush(stdout);
+ fflush(stderr);
return 0;
}
static int runChild2(kwsysProcess* kp,
const char* cmd[], int state, int exception, int value,
int share, int output, int delay, double timeout,
- int poll, int disown)
+ int poll, int disown, int createNewGroup,
+ unsigned int interruptDelay)
{
int result = 0;
char* data = 0;
@@ -249,6 +382,10 @@ static int runChild2(kwsysProcess* kp,
{
kwsysProcess_SetOption(kp, kwsysProcess_Option_Detach, 1);
}
+ if(createNewGroup)
+ {
+ kwsysProcess_SetOption(kp, kwsysProcess_Option_CreateProcessGroup, 1);
+ }
kwsysProcess_Execute(kp);
if(poll)
@@ -256,6 +393,12 @@ static int runChild2(kwsysProcess* kp,
pUserTimeout = &userTimeout;
}
+ if(interruptDelay)
+ {
+ testProcess_sleep(interruptDelay);
+ kwsysProcess_Interrupt(kp);
+ }
+
if(!share && !disown)
{
int p;
@@ -286,17 +429,13 @@ static int runChild2(kwsysProcess* kp,
if(poll)
{
/* Delay to avoid busy loop during polling. */
-#if defined(_WIN32)
- Sleep(100);
-#else
testProcess_usleep(100000);
-#endif
}
if(delay)
{
/* Purposely sleeping only on Win32 to let pipe fill up. */
#if defined(_WIN32)
- Sleep(100);
+ testProcess_usleep(100000);
#endif
}
}
@@ -337,7 +476,7 @@ static int runChild2(kwsysProcess* kp,
printf("Error in administrating child process: [%s]\n",
kwsysProcess_GetErrorString(kp)); break;
};
-
+
if(result)
{
if(exception != kwsysProcess_GetExitException(kp))
@@ -353,7 +492,7 @@ static int runChild2(kwsysProcess* kp,
value, kwsysProcess_GetExitValue(kp));
}
}
-
+
if(kwsysProcess_GetState(kp) != state)
{
fprintf(stderr, "Mismatch in state. "
@@ -374,9 +513,37 @@ static int runChild2(kwsysProcess* kp,
return result;
}
+/**
+ * Runs a child process and blocks until it returns. Arguments as follows:
+ *
+ * cmd = Command line to run.
+ * state = Expected return value of kwsysProcess_GetState after exit.
+ * exception = Expected return value of kwsysProcess_GetExitException.
+ * value = Expected return value of kwsysProcess_GetExitValue.
+ * share = Whether to share stdout/stderr child pipes with our pipes
+ * by way of kwsysProcess_SetPipeShared. If false, new pipes
+ * are created.
+ * output = If !share && !disown, whether to write the child's stdout
+ * and stderr output to our stdout.
+ * delay = If !share && !disown, adds an additional short delay to
+ * the pipe loop to allow the pipes to fill up; Windows only.
+ * timeout = Non-zero to sets a timeout in seconds via
+ * kwsysProcess_SetTimeout.
+ * poll = If !share && !disown, we count the number of 0.1 second
+ * intervals where the child pipes had no new data. We fail
+ * if not in the bounds of MINPOLL/MAXPOLL.
+ * repeat = Number of times to run the process.
+ * disown = If set, the process is disowned.
+ * createNewGroup = If set, the process is created in a new process group.
+ * interruptDelay = If non-zero, number of seconds to delay before
+ * interrupting the process. Note that this delay will occur
+ * BEFORE any reading/polling of pipes occurs and before any
+ * detachment occurs.
+ */
int runChild(const char* cmd[], int state, int exception, int value,
int share, int output, int delay, double timeout,
- int poll, int repeat, int disown)
+ int poll, int repeat, int disown, int createNewGroup,
+ unsigned int interruptDelay)
{
int result = 1;
kwsysProcess* kp = kwsysProcess_New();
@@ -388,7 +555,8 @@ int runChild(const char* cmd[], int state, int exception, int value,
while(repeat-- > 0)
{
result = runChild2(kp, cmd, state, exception, value, share,
- output, delay, timeout, poll, disown);
+ output, delay, timeout, poll, disown, createNewGroup,
+ interruptDelay);
}
kwsysProcess_Delete(kp);
return result;
@@ -435,7 +603,7 @@ int main(int argc, const char* argv[])
n = atoi(argv[2]);
}
/* Check arguments. */
- if(((n >= 1 && n <= 8) || n == 108) && argc == 3)
+ if(((n >= 1 && n <= 10) || n == 108 || n == 109 || n == 110) && argc == 3)
{
/* This is the child process for a requested test number. */
switch (n)
@@ -448,15 +616,19 @@ int main(int argc, const char* argv[])
case 6: test6(argc, argv); return 0;
case 7: return test7(argc, argv);
case 8: return test8(argc, argv);
+ case 9: return test9(argc, argv);
+ case 10: return test10(argc, argv);
case 108: return test8_grandchild(argc, argv);
+ case 109: return test9_grandchild(argc, argv);
+ case 110: return test10_grandchild(argc, argv);
}
fprintf(stderr, "Invalid test number %d.\n", n);
return 1;
}
- else if(n >= 1 && n <= 8)
+ else if(n >= 1 && n <= 10)
{
/* This is the parent process for a requested test number. */
- int states[8] =
+ int states[10] =
{
kwsysProcess_State_Exited,
kwsysProcess_State_Exited,
@@ -465,9 +637,11 @@ int main(int argc, const char* argv[])
kwsysProcess_State_Exited,
kwsysProcess_State_Expired,
kwsysProcess_State_Exited,
- kwsysProcess_State_Exited
+ kwsysProcess_State_Exited,
+ kwsysProcess_State_Expired, /* Ctrl+C handler test */
+ kwsysProcess_State_Exception /* Process group test */
};
- int exceptions[8] =
+ int exceptions[10] =
{
kwsysProcess_Exception_None,
kwsysProcess_Exception_None,
@@ -476,14 +650,19 @@ int main(int argc, const char* argv[])
kwsysProcess_Exception_None,
kwsysProcess_Exception_None,
kwsysProcess_Exception_None,
- kwsysProcess_Exception_None
+ kwsysProcess_Exception_None,
+ kwsysProcess_Exception_None,
+ kwsysProcess_Exception_Interrupt
};
- int values[8] = {0, 123, 1, 1, 0, 0, 0, 0};
- int outputs[8] = {1, 1, 1, 1, 1, 0, 1, 1};
- int delays[8] = {0, 0, 0, 0, 0, 1, 0, 0};
- double timeouts[8] = {10, 10, 10, 30, 30, 10, -1, 10};
- int polls[8] = {0, 0, 0, 0, 0, 0, 1, 0};
- int repeat[8] = {2, 1, 1, 1, 1, 1, 1, 1};
+ int values[10] = {0, 123, 1, 1, 0, 0, 0, 0, 1, 1};
+ int shares[10] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1};
+ int outputs[10] = {1, 1, 1, 1, 1, 0, 1, 1, 1, 1};
+ int delays[10] = {0, 0, 0, 0, 0, 1, 0, 0, 0, 0};
+ double timeouts[10] = {10, 10, 10, 30, 30, 10, -1, 10, 6, 4};
+ int polls[10] = {0, 0, 0, 0, 0, 0, 1, 0, 0, 0};
+ int repeat[10] = {2, 1, 1, 1, 1, 1, 1, 1, 1, 1};
+ int createNewGroups[10] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1};
+ unsigned int interruptDelays[10] = {0, 0, 0, 0, 0, 0, 0, 0, 3, 2};
int r;
const char* cmd[4];
#ifdef _WIN32
@@ -515,9 +694,10 @@ int main(int argc, const char* argv[])
fprintf(stderr, "Output on stderr before test %d.\n", n);
fflush(stdout);
fflush(stderr);
- r = runChild(cmd, states[n-1], exceptions[n-1], values[n-1], 0,
+ r = runChild(cmd, states[n-1], exceptions[n-1], values[n-1], shares[n-1],
outputs[n-1], delays[n-1], timeouts[n-1],
- polls[n-1], repeat[n-1], 0);
+ polls[n-1], repeat[n-1], 0, createNewGroups[n-1],
+ interruptDelays[n-1]);
fprintf(stdout, "Output on stdout after test %d.\n", n);
fprintf(stderr, "Output on stderr after test %d.\n", n);
fflush(stdout);
@@ -536,7 +716,8 @@ int main(int argc, const char* argv[])
int exception = kwsysProcess_Exception_None;
int value = 0;
double timeout = 0;
- int r = runChild(cmd, state, exception, value, 0, 1, 0, timeout, 0, 1, 0);
+ int r = runChild(cmd, state, exception, value, 0, 1, 0, timeout,
+ 0, 1, 0, 0, 0);
return r;
}
else
diff --git a/Source/kwsys/testSystemTools.cxx b/Source/kwsys/testSystemTools.cxx
index 15d8eab..7b5c025 100644
--- a/Source/kwsys/testSystemTools.cxx
+++ b/Source/kwsys/testSystemTools.cxx
@@ -98,6 +98,10 @@ static bool CheckEscapeChars(kwsys_stl::string input,
static bool CheckFileOperations()
{
bool res = true;
+ const kwsys_stl::string testNonExistingFile(TEST_SYSTEMTOOLS_SOURCE_DIR
+ "/testSystemToolsNonExistingFile");
+ const kwsys_stl::string testDotFile(TEST_SYSTEMTOOLS_SOURCE_DIR
+ "/.");
const kwsys_stl::string testBinFile(TEST_SYSTEMTOOLS_SOURCE_DIR
"/testSystemTools.bin");
const kwsys_stl::string testTxtFile(TEST_SYSTEMTOOLS_SOURCE_DIR
@@ -106,6 +110,24 @@ static bool CheckFileOperations()
"/testSystemToolsNewDir");
const kwsys_stl::string testNewFile(testNewDir + "/testNewFile.txt");
+ if (kwsys::SystemTools::DetectFileType(testNonExistingFile.c_str()) !=
+ kwsys::SystemTools::FileTypeUnknown)
+ {
+ kwsys_ios::cerr
+ << "Problem with DetectFileType - failed to detect type of: "
+ << testNonExistingFile << kwsys_ios::endl;
+ res = false;
+ }
+
+ if (kwsys::SystemTools::DetectFileType(testDotFile.c_str()) !=
+ kwsys::SystemTools::FileTypeUnknown)
+ {
+ kwsys_ios::cerr
+ << "Problem with DetectFileType - failed to detect type of: "
+ << testDotFile << kwsys_ios::endl;
+ res = false;
+ }
+
if (kwsys::SystemTools::DetectFileType(testBinFile.c_str()) !=
kwsys::SystemTools::FileTypeBinary)
{
diff --git a/Tests/BuildDepends/CMakeLists.txt b/Tests/BuildDepends/CMakeLists.txt
index 7b7353c..36987de 100644
--- a/Tests/BuildDepends/CMakeLists.txt
+++ b/Tests/BuildDepends/CMakeLists.txt
@@ -34,7 +34,7 @@ if(WIN32 AND "${CMAKE_CXX_COMPILER_ID}" MATCHES "Intel")
set(_cmake_options "-DCMAKE_EXE_LINKER_FLAGS=")
endif()
-if("${CMAKE_GENERATOR}" MATCHES "Make")
+if("${CMAKE_GENERATOR}" MATCHES "Make|Ninja")
set(TEST_LINK_DEPENDS ${BuildDepends_BINARY_DIR}/Project/linkdep.txt)
file(WRITE ${TEST_LINK_DEPENDS} "1")
endif()
diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt
index d95a5f4..35b29bf 100644
--- a/Tests/CMakeLists.txt
+++ b/Tests/CMakeLists.txt
@@ -1333,6 +1333,10 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release
add_subdirectory(FindJsonCpp)
endif()
+ if(CMake_TEST_FindOpenSSL)
+ add_subdirectory(FindOpenSSL)
+ endif()
+
# Matlab module
if(CMake_TEST_FindMatlab)
ADD_TEST_MACRO(FindMatlab.basic_checks ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>)
@@ -3008,17 +3012,30 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release
if(JNI_H AND EXISTS "${JNI_H}") # in case jni.h is a broken symlink
file(READ "${JNI_H}" JNI_FILE)
if("${JNI_FILE}" MATCHES "JDK1_2")
- add_test(Java ${CMAKE_CTEST_COMMAND}
+ add_test(Java.Jar ${CMAKE_CTEST_COMMAND}
--build-and-test
"${CMake_SOURCE_DIR}/Tests/Java"
- "${CMake_BINARY_DIR}/Tests/Java"
+ "${CMake_BINARY_DIR}/Tests/JavaJar"
${build_generator_args}
--build-project hello
+ --build-target hello
--build-two-config
- --build-run-dir "${CMake_BINARY_DIR}/Tests/Java/"
+ --build-run-dir "${CMake_BINARY_DIR}/Tests/JavaJar/"
--build-options ${build_options}
--test-command ${JAVA_RUNTIME} -classpath hello.jar HelloWorld)
- list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/Java")
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/JavaJar")
+ add_test(Java.JarSourceList ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/Java"
+ "${CMake_BINARY_DIR}/Tests/JavaJarSourceList"
+ ${build_generator_args}
+ --build-project hello
+ --build-target hello2
+ --build-two-config
+ --build-run-dir "${CMake_BINARY_DIR}/Tests/JavaJarSourceList/"
+ --build-options ${build_options}
+ --test-command ${JAVA_RUNTIME} -classpath hello2.jar HelloWorld)
+ list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/JavaJarSourceList")
endif()
endif()
endif()
diff --git a/Tests/CMakeOnly/Test.cmake.in b/Tests/CMakeOnly/Test.cmake.in
index 8d3258b..0ae8af1 100644
--- a/Tests/CMakeOnly/Test.cmake.in
+++ b/Tests/CMakeOnly/Test.cmake.in
@@ -2,6 +2,11 @@ if (NOT TEST_SOURCE)
set(TEST_SOURCE "${TEST}")
endif ()
+set(make_program "@CMake_TEST_EXPLICIT_MAKE_PROGRAM@")
+if(make_program)
+ set(maybe_make_program "-DCMAKE_MAKE_PROGRAM=${make_program}")
+endif()
+
set(source_dir "@CMAKE_CURRENT_SOURCE_DIR@/${TEST_SOURCE}")
set(binary_dir "@CMAKE_CURRENT_BINARY_DIR@/${TEST}-build")
file(REMOVE_RECURSE "${binary_dir}")
@@ -11,6 +16,7 @@ execute_process(
"${source_dir}" -G "@CMAKE_GENERATOR@"
-A "@CMAKE_GENERATOR_PLATFORM@"
-T "@CMAKE_GENERATOR_TOOLSET@"
+ ${maybe_make_program}
WORKING_DIRECTORY "${binary_dir}"
RESULT_VARIABLE result
)
diff --git a/Tests/CTestTest2/test.cmake.in b/Tests/CTestTest2/test.cmake.in
index 852bb6b..825b957 100644
--- a/Tests/CTestTest2/test.cmake.in
+++ b/Tests/CTestTest2/test.cmake.in
@@ -39,14 +39,19 @@ CMAKE_CXX_COMPILER_ARG1:STRING=@CMAKE_CXX_COMPILER_ARG1@
CTEST_TEST_KWSYS:BOOL=ON
")
+set(test_exclude
+ kwsys.testProcess-10
+ )
+
CTEST_START(Experimental)
#CTEST_UPDATE(SOURCE "${CTEST_SOURCE_DIRECTORY}" RETURN_VALUE res)
CTEST_CONFIGURE(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
+CTEST_READ_CUSTOM_FILES(${CTEST_BINARY_DIRECTORY})
CTEST_BUILD(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
-CTEST_TEST(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res START 1 END 5 STRIDE 2)
-CTEST_TEST(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res START 7 STRIDE 2 SUBMIT_INDEX 1)
-CTEST_TEST(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res START 2 END 4 STRIDE 2 SUBMIT_INDEX 2)
-CTEST_TEST(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res START 6 STRIDE 2 SUBMIT_INDEX 3)
+CTEST_TEST(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res EXCLUDE ${test_exclude} START 1 END 5 STRIDE 2)
+CTEST_TEST(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res EXCLUDE ${test_exclude} START 7 STRIDE 2 SUBMIT_INDEX 1)
+CTEST_TEST(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res EXCLUDE ${test_exclude} START 2 END 4 STRIDE 2 SUBMIT_INDEX 2)
+CTEST_TEST(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res EXCLUDE ${test_exclude} START 6 STRIDE 2 SUBMIT_INDEX 3)
CTEST_MEMCHECK(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res STRIDE 1.5)
CTEST_COVERAGE(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
diff --git a/Tests/ExportImport/Export/CMakeLists.txt b/Tests/ExportImport/Export/CMakeLists.txt
index df3f178..7fdfaa8 100644
--- a/Tests/ExportImport/Export/CMakeLists.txt
+++ b/Tests/ExportImport/Export/CMakeLists.txt
@@ -105,6 +105,19 @@ target_link_libraries(testLib4
add_executable(testExe3 testExe3.c)
set_property(TARGET testExe3 PROPERTY MACOSX_BUNDLE 1)
+# Test <ARCHIVE|LIBRARY|RUNTIME>_OUTPUT_DIRECTORY[_<CONFIG>] properties with generator expressions
+add_executable(testExe4 testExe4.c)
+target_link_libraries(testExe4 testExe1lib)
+set_property(TARGET testLib7 PROPERTY ARCHIVE_OUTPUT_DIRECTORY_DEBUG testLib7D-$<CONFIG>)
+set_property(TARGET testLib7 PROPERTY ARCHIVE_OUTPUT_DIRECTORY_RELEASE testLib7R-$<CONFIG>)
+set_property(TARGET testLib7 PROPERTY ARCHIVE_OUTPUT_DIRECTORY testLib7-$<CONFIG>)
+set_property(TARGET testLib5 PROPERTY LIBRARY_OUTPUT_DIRECTORY_DEBUG testLib5D-$<CONFIG>)
+set_property(TARGET testLib5 PROPERTY LIBRARY_OUTPUT_DIRECTORY_RELEASE testLib5R-$<CONFIG>)
+set_property(TARGET testLib5 PROPERTY LIBRARY_OUTPUT_DIRECTORY testLib5-$<CONFIG>)
+set_property(TARGET testExe4 PROPERTY RUNTIME_OUTPUT_DIRECTORY_DEBUG testExe4D-$<CONFIG>)
+set_property(TARGET testExe4 PROPERTY RUNTIME_OUTPUT_DIRECTORY_RELEASE testExe4R-$<CONFIG>)
+set_property(TARGET testExe4 PROPERTY RUNTIME_OUTPUT_DIRECTORY testExe4-$<CONFIG>)
+
# Test cyclic dependencies.
add_library(testLibCycleA STATIC
testLibCycleA1.c testLibCycleA2.c testLibCycleA3.c)
@@ -450,7 +463,7 @@ install(FILES
# Install and export from install tree.
install(
TARGETS
- testExe1 testLib1 testLib2 testExe2 testLib3 testLib4 testExe3
+ testExe1 testLib1 testLib2 testExe2 testLib3 testLib4 testExe3 testExe4
testExe2lib testLib4lib testLib4libdbg testLib4libopt
testLib6 testLib7
testLibCycleA testLibCycleB
@@ -511,7 +524,7 @@ export(TARGETS testExe1 testLib1 testLib2 testLib3
NAMESPACE bld_
FILE ExportBuildTree.cmake
)
-export(TARGETS testExe2 testLib4 testLib5 testLib6 testLib7 testExe3 testExe2lib
+export(TARGETS testExe2 testLib4 testLib5 testLib6 testLib7 testExe3 testExe4 testExe2lib
testLib4lib testLib4libdbg testLib4libopt
testLibCycleA testLibCycleB
testLibPerConfigDest
diff --git a/Tests/ExportImport/Export/testExe4.c b/Tests/ExportImport/Export/testExe4.c
new file mode 100644
index 0000000..731057e
--- /dev/null
+++ b/Tests/ExportImport/Export/testExe4.c
@@ -0,0 +1,24 @@
+#include <stdio.h>
+
+int main(int argc, const char* argv[])
+{
+ if(argc < 2)
+ {
+ fprintf(stderr, "Must specify output file.\n");
+ return 1;
+ }
+ {
+ FILE* f = fopen(argv[1], "w");
+ if(f)
+ {
+ fprintf(f, "int generated_by_testExe4() { return 0; }\n");
+ fclose(f);
+ }
+ else
+ {
+ fprintf(stderr, "Error writing to %s\n", argv[1]);
+ return 1;
+ }
+ }
+ return 0;
+}
diff --git a/Tests/ExportImport/Import/A/CMakeLists.txt b/Tests/ExportImport/Import/A/CMakeLists.txt
index a74bad1..0f56495 100644
--- a/Tests/ExportImport/Import/A/CMakeLists.txt
+++ b/Tests/ExportImport/Import/A/CMakeLists.txt
@@ -19,11 +19,17 @@ add_custom_command(
COMMAND exp_testExe3 ${Import_BINARY_DIR}/exp_generated3.c
DEPENDS exp_testExe3
)
+add_custom_command(
+ OUTPUT ${Import_BINARY_DIR}/exp_generated4.c
+ COMMAND exp_testExe4 ${Import_BINARY_DIR}/exp_generated4.c
+ DEPENDS exp_testExe4
+ )
add_executable(imp_testExe1
imp_testExe1.c
${Import_BINARY_DIR}/exp_generated.c
${Import_BINARY_DIR}/exp_generated3.c
+ ${Import_BINARY_DIR}/exp_generated4.c
)
# Try linking to a library imported from the install tree.
@@ -53,11 +59,17 @@ add_custom_command(
COMMAND bld_testExe3 ${Import_BINARY_DIR}/bld_generated3.c
DEPENDS bld_testExe3
)
+add_custom_command(
+ OUTPUT ${Import_BINARY_DIR}/bld_generated4.c
+ COMMAND bld_testExe4 ${Import_BINARY_DIR}/bld_generated4.c
+ DEPENDS bld_testExe4
+ )
add_executable(imp_testExe1b
imp_testExe1.c
${Import_BINARY_DIR}/bld_generated.c
${Import_BINARY_DIR}/bld_generated3.c
+ ${Import_BINARY_DIR}/bld_generated4.c
)
# Try linking to a library imported from the build tree.
diff --git a/Tests/ExportImport/Import/A/imp_testExe1.c b/Tests/ExportImport/Import/A/imp_testExe1.c
index 56cdd2c..0a74309 100644
--- a/Tests/ExportImport/Import/A/imp_testExe1.c
+++ b/Tests/ExportImport/Import/A/imp_testExe1.c
@@ -1,5 +1,6 @@
extern int generated_by_testExe1();
extern int generated_by_testExe3();
+extern int generated_by_testExe4();
extern int testLib2();
extern int testLib3();
extern int testLib4();
@@ -24,5 +25,5 @@ int main()
return (testLib2() + generated_by_testExe1() + testLib3() + testLib4()
+ testLib5() + testLib6() + testLib7() + testLibCycleA1()
+ testLibPerConfigDest()
- + generated_by_testExe3() + testLib4lib() + testLib4libcfg());
+ + generated_by_testExe3() + generated_by_testExe4() + testLib4lib() + testLib4libcfg());
}
diff --git a/Tests/FindOpenSSL/CMakeLists.txt b/Tests/FindOpenSSL/CMakeLists.txt
new file mode 100644
index 0000000..66b3fb2
--- /dev/null
+++ b/Tests/FindOpenSSL/CMakeLists.txt
@@ -0,0 +1,9 @@
+add_test(NAME FindOpenSSL.rand COMMAND ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindOpenSSL/rand"
+ "${CMake_BINARY_DIR}/Tests/FindOpenSSL/rand"
+ ${build_generator_args}
+ --build-project FindOpenSSL_rand
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V
+ )
diff --git a/Tests/FindOpenSSL/rand/CMakeLists.txt b/Tests/FindOpenSSL/rand/CMakeLists.txt
new file mode 100644
index 0000000..520d5d2
--- /dev/null
+++ b/Tests/FindOpenSSL/rand/CMakeLists.txt
@@ -0,0 +1,14 @@
+cmake_minimum_required(VERSION 3.0)
+project(FindOpenSSL_rand CXX)
+include(CTest)
+
+find_package(OpenSSL REQUIRED)
+
+add_executable(tstopensslrand_tgt main.cc)
+target_link_libraries(tstopensslrand_tgt OpenSSL::SSL)
+add_test(NAME tstopensslrand_tgt COMMAND tstopensslrand_tgt)
+
+add_executable(tstopensslrand_var main.cc)
+target_link_libraries(tstopensslrand_var ${OPENSSL_LIBRARIES})
+target_include_directories(tstopensslrand_var PRIVATE ${OPENSSL_INCLUDE_DIR})
+add_test(NAME tstopensslrand_var COMMAND tstopensslrand_var)
diff --git a/Tests/FindOpenSSL/rand/main.cc b/Tests/FindOpenSSL/rand/main.cc
new file mode 100644
index 0000000..a5d1ac0
--- /dev/null
+++ b/Tests/FindOpenSSL/rand/main.cc
@@ -0,0 +1,22 @@
+#include <openssl/rand.h>
+
+int main()
+{
+ // return value
+ int retval = 1;
+
+ // bytes buffer
+ unsigned char buf[1024];
+
+ // random bytes
+ int rezval = RAND_bytes(buf, sizeof(buf)); /* 1 succes, 0 otherwise */
+
+ // check result
+ if(rezval == 1)
+ {
+ retval = 0;
+ }
+
+ // return code
+ return retval;
+}
diff --git a/Tests/FortranC/Flags.cmake.in b/Tests/FortranC/Flags.cmake.in
index 2300fc6..cf361a5 100644
--- a/Tests/FortranC/Flags.cmake.in
+++ b/Tests/FortranC/Flags.cmake.in
@@ -12,11 +12,17 @@ configure_file("${src}/test_opt.sh.in" "${bld}/fc.sh" @ONLY)
set(ID)
set(COMMAND)
+set(make_program "@CMake_TEST_EXPLICIT_MAKE_PROGRAM@")
+if(make_program)
+ set(maybe_make_program "-DCMAKE_MAKE_PROGRAM=${make_program}")
+endif()
+
execute_process(
WORKING_DIRECTORY "${bld}"
COMMAND ${CMAKE_COMMAND} "${src}" -G "@CMAKE_GENERATOR@"
-A "@CMAKE_GENERATOR_PLATFORM@"
-T "@CMAKE_GENERATOR_TOOLSET@"
+ ${maybe_make_program}
"-DFortranC_TEST_FLAGS=1"
"-DCMAKE_C_COMPILER=${bld}/cc.sh"
"-DCMAKE_C_FLAGS:STRING=@CMAKE_C_FLAGS@"
diff --git a/Tests/IncludeDirectories/SystemIncludeDirectories/CMakeLists.txt b/Tests/IncludeDirectories/SystemIncludeDirectories/CMakeLists.txt
index 0215e93..dcee85e 100644
--- a/Tests/IncludeDirectories/SystemIncludeDirectories/CMakeLists.txt
+++ b/Tests/IncludeDirectories/SystemIncludeDirectories/CMakeLists.txt
@@ -35,6 +35,16 @@ add_library(imported_consumer2 imported_consumer.cpp)
target_link_libraries(imported_consumer2 imported_consumer)
target_compile_options(imported_consumer2 PRIVATE -Werror=unused-variable)
+# add a target which has a relative system include
+add_library(somelib imported_consumer.cpp)
+target_include_directories(somelib SYSTEM PUBLIC "systemlib_header_only")
+target_compile_options(somelib PRIVATE -Werror=unused-variable)
+
+# add a target which consumes a relative system include
+add_library(otherlib upstream.cpp)
+target_link_libraries(otherlib PUBLIC somelib)
+target_compile_options(somelib PRIVATE -Werror=unused-variable)
+
macro(do_try_compile error_option)
set(TC_ARGS
IFACE_TRY_COMPILE_${error_option}
diff --git a/Tests/Java/CMakeLists.txt b/Tests/Java/CMakeLists.txt
index 6a69a24..e1bcf3c 100644
--- a/Tests/Java/CMakeLists.txt
+++ b/Tests/Java/CMakeLists.txt
@@ -7,3 +7,7 @@ find_package(Java COMPONENTS Development)
include (UseJava)
add_jar(hello A.java HelloWorld.java)
+
+# use listing file to specify sources
+file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/java_fileslist "A.java\nHelloWorld.java\n")
+add_jar(hello2 @${CMAKE_CURRENT_BINARY_DIR}/java_fileslist)
diff --git a/Tests/RunCMake/CMP0064/CMP0064-NEW.cmake b/Tests/RunCMake/CMP0064/CMP0064-NEW.cmake
new file mode 100644
index 0000000..cdf50e9
--- /dev/null
+++ b/Tests/RunCMake/CMP0064/CMP0064-NEW.cmake
@@ -0,0 +1,5 @@
+cmake_policy(SET CMP0064 NEW)
+
+if(NOT TEST TestThatDoesNotExist)
+ message(STATUS "if NOT TestThatDoesNotExist is true")
+endif()
diff --git a/Tests/RunCMake/CMP0064/CMP0064-OLD.cmake b/Tests/RunCMake/CMP0064/CMP0064-OLD.cmake
new file mode 100644
index 0000000..bffd3f3
--- /dev/null
+++ b/Tests/RunCMake/CMP0064/CMP0064-OLD.cmake
@@ -0,0 +1,7 @@
+cmake_policy(SET CMP0064 OLD)
+
+if(TEST)
+ message(FATAL_ERROR "TEST was not recognized to be undefined")
+else()
+ message(STATUS "TEST was treated as a variable")
+endif()
diff --git a/Tests/RunCMake/CMP0064/CMP0064-WARN.cmake b/Tests/RunCMake/CMP0064/CMP0064-WARN.cmake
new file mode 100644
index 0000000..bffd3f3
--- /dev/null
+++ b/Tests/RunCMake/CMP0064/CMP0064-WARN.cmake
@@ -0,0 +1,7 @@
+cmake_policy(SET CMP0064 OLD)
+
+if(TEST)
+ message(FATAL_ERROR "TEST was not recognized to be undefined")
+else()
+ message(STATUS "TEST was treated as a variable")
+endif()
diff --git a/Tests/RunCMake/CMP0064/CMakeLists.txt b/Tests/RunCMake/CMP0064/CMakeLists.txt
new file mode 100644
index 0000000..74b3ff8
--- /dev/null
+++ b/Tests/RunCMake/CMP0064/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.3)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/CMP0064/RunCMakeTest.cmake b/Tests/RunCMake/CMP0064/RunCMakeTest.cmake
new file mode 100644
index 0000000..26e0a91
--- /dev/null
+++ b/Tests/RunCMake/CMP0064/RunCMakeTest.cmake
@@ -0,0 +1,5 @@
+include(RunCMake)
+
+run_cmake(CMP0064-OLD)
+run_cmake(CMP0064-WARN)
+run_cmake(CMP0064-NEW)
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index 607e799..c274d8f 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -103,6 +103,7 @@ add_RunCMake_test(CMP0055)
add_RunCMake_test(CMP0057)
add_RunCMake_test(CMP0059)
add_RunCMake_test(CMP0060)
+add_RunCMake_test(CMP0064)
if(CMAKE_GENERATOR MATCHES "Make")
add_RunCMake_test(Make)
endif()
@@ -145,6 +146,7 @@ add_RunCMake_test(TargetSources)
add_RunCMake_test(find_dependency)
add_RunCMake_test(CompileDefinitions)
add_RunCMake_test(CompileFeatures)
+add_RunCMake_test(PolicyScope)
add_RunCMake_test(WriteCompilerDetectionHeader)
if(NOT WIN32)
add_RunCMake_test(PositionIndependentCode)
@@ -161,6 +163,7 @@ add_RunCMake_test(Syntax)
add_RunCMake_test(add_custom_command)
add_RunCMake_test(add_custom_target)
add_RunCMake_test(add_dependencies)
+add_RunCMake_test(add_subdirectory)
add_RunCMake_test(build_command)
add_RunCMake_test(execute_process)
add_RunCMake_test(export)
diff --git a/Tests/RunCMake/CPack/CMakeLists.txt b/Tests/RunCMake/CPack/CMakeLists.txt
index 7905706..46f1367 100644
--- a/Tests/RunCMake/CPack/CMakeLists.txt
+++ b/Tests/RunCMake/CPack/CMakeLists.txt
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
-project(${RunCMake_TEST} NONE)
+project(${RunCMake_TEST} CXX)
include(${RunCMake_TEST}.cmake)
# include test generator specifics
diff --git a/Tests/RunCMake/CPack/DEB/DEPENDENCIES-ExpectedFiles.cmake b/Tests/RunCMake/CPack/DEB/DEPENDENCIES-ExpectedFiles.cmake
new file mode 100644
index 0000000..c56c670
--- /dev/null
+++ b/Tests/RunCMake/CPack/DEB/DEPENDENCIES-ExpectedFiles.cmake
@@ -0,0 +1,14 @@
+set(whitespaces_ "[\t\n\r ]*")
+
+set(EXPECTED_FILES_COUNT "5")
+set(EXPECTED_FILE_1 "dependencies*-applications.deb")
+set(EXPECTED_FILE_CONTENT_1 "^.*/usr/foo${whitespaces_}.*/usr/foo/test_prog$")
+set(EXPECTED_FILE_2 "dependencies*-applications_auto.deb")
+set(EXPECTED_FILE_CONTENT_2 "^.*/usr/foo_auto${whitespaces_}.*/usr/foo_auto/test_prog$")
+set(EXPECTED_FILE_3 "dependencies*-headers.deb")
+set(EXPECTED_FILE_CONTENT_3 "^.*/usr/bar${whitespaces_}.*/usr/bar/CMakeLists.txt$")
+set(EXPECTED_FILE_4 "dependencies*-libs.deb")
+# dynamic lib extension is .so on Linux and .dylib on Mac so we will use a wildcard .* for it
+set(EXPECTED_FILE_CONTENT_4 "^.*/usr/bas${whitespaces_}.*/usr/bas/libtest_lib\\..*$")
+set(EXPECTED_FILE_5 "dependencies*-libs_auto.deb")
+set(EXPECTED_FILE_CONTENT_5 "^.*/usr/bas_auto${whitespaces_}.*/usr/bas_auto/libtest_lib\\..*$")
diff --git a/Tests/RunCMake/CPack/DEB/DEPENDENCIES-VerifyResult.cmake b/Tests/RunCMake/CPack/DEB/DEPENDENCIES-VerifyResult.cmake
new file mode 100644
index 0000000..44c862d
--- /dev/null
+++ b/Tests/RunCMake/CPack/DEB/DEPENDENCIES-VerifyResult.cmake
@@ -0,0 +1,15 @@
+function(checkDepends_ FILE REGEX)
+ set(whitespaces_ "[\t\n\r ]*")
+
+ getPackageInfo("${FILE}" "FILE_INFO_")
+ if(NOT FILE_INFO_ MATCHES "${REGEX}")
+ message(FATAL_ERROR "Unexpected dependencies in '${FILE}'; file info: '${FILE_INFO_}'")
+ endif()
+endfunction()
+
+checkDepends_("${FOUND_FILE_1}" ".*Depends${whitespaces_}:${whitespaces_}depend-application, depend-application-b.*")
+# use wildcard as we are using dependency auto detection
+checkDepends_("${FOUND_FILE_2}" ".*Depends${whitespaces_}:${whitespaces_}.*depend-application, depend-application-b.*")
+checkDepends_("${FOUND_FILE_3}" ".*Depends${whitespaces_}:${whitespaces_}depend-headers.*")
+checkDepends_("${FOUND_FILE_4}" ".*Depends${whitespaces_}:${whitespaces_}depend-default, depend-default-b.*")
+checkDepends_("${FOUND_FILE_5}" ".*Depends${whitespaces_}:${whitespaces_}depend-default, depend-default-b.*")
diff --git a/Tests/RunCMake/CPack/DEB/DEPENDENCIES-specifics.cmake b/Tests/RunCMake/CPack/DEB/DEPENDENCIES-specifics.cmake
new file mode 100644
index 0000000..9e09428
--- /dev/null
+++ b/Tests/RunCMake/CPack/DEB/DEPENDENCIES-specifics.cmake
@@ -0,0 +1,15 @@
+set(CPACK_PACKAGE_CONTACT "someone")
+set(CPACK_DEB_COMPONENT_INSTALL "ON")
+
+# false by default
+set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS FALSE)
+# FIXME can not be tested as libraries first have to be part of a package in order
+# to determine their dependencies and we can not be certain if there will be any
+set(CPACK_DEBIAN_APPLICATIONS_AUTO_PACKAGE_SHLIBDEPS TRUE)
+
+set(CPACK_DEBIAN_PACKAGE_DEPENDS "depend-default, depend-default-b")
+set(CPACK_DEBIAN_APPLICATIONS_PACKAGE_DEPENDS "depend-application, depend-application-b")
+set(CPACK_DEBIAN_APPLICATIONS_AUTO_PACKAGE_DEPENDS "depend-application, depend-application-b")
+set(CPACK_DEBIAN_HEADERS_PACKAGE_DEPENDS "depend-headers")
+
+# TODO add other dependency tests once CPackDeb supports them
diff --git a/Tests/RunCMake/CPack/DEB/Helpers.cmake b/Tests/RunCMake/CPack/DEB/Helpers.cmake
index 45c85c3..a204a3c 100644
--- a/Tests/RunCMake/CPack/DEB/Helpers.cmake
+++ b/Tests/RunCMake/CPack/DEB/Helpers.cmake
@@ -26,3 +26,13 @@ function(verifyDebControl FILE PREFIX VERIFY_FILES)
endif()
endforeach()
endfunction()
+
+function(getPackageInfo FILE RESULT_VAR)
+ execute_process(COMMAND ${DPKG_EXECUTABLE} -I ${FILE}
+ WORKING_DIRECTORY "${CPACK_TEMPORARY_DIRECTORY}"
+ OUTPUT_VARIABLE package_info_
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+ set(${RESULT_VAR} "${package_info_}" PARENT_SCOPE)
+endfunction()
diff --git a/Tests/RunCMake/CPack/DEPENDENCIES.cmake b/Tests/RunCMake/CPack/DEPENDENCIES.cmake
new file mode 100644
index 0000000..0aef925
--- /dev/null
+++ b/Tests/RunCMake/CPack/DEPENDENCIES.cmake
@@ -0,0 +1,18 @@
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test_lib.hpp"
+ "int test_lib();")
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test_lib.cpp"
+ "#include \"test_lib.hpp\"\nint test_lib() {return 0;}")
+add_library(test_lib SHARED "${CMAKE_CURRENT_BINARY_DIR}/test_lib.cpp")
+
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/main.cpp"
+ "#include \"test_lib.hpp\"\nint main() {return test_lib();}")
+add_executable(test_prog "${CMAKE_CURRENT_BINARY_DIR}/main.cpp")
+target_link_libraries(test_prog test_lib)
+
+install(TARGETS test_prog DESTINATION foo COMPONENT applications)
+install(TARGETS test_prog DESTINATION foo_auto COMPONENT applications_auto)
+install(FILES CMakeLists.txt DESTINATION bar COMPONENT headers)
+install(TARGETS test_lib DESTINATION bas COMPONENT libs)
+install(TARGETS test_lib DESTINATION bas_auto COMPONENT libs_auto)
+
+set(CPACK_PACKAGE_NAME "dependencies")
diff --git a/Tests/RunCMake/CPack/RPM/DEPENDENCIES-ExpectedFiles.cmake b/Tests/RunCMake/CPack/RPM/DEPENDENCIES-ExpectedFiles.cmake
new file mode 100644
index 0000000..cf85dab
--- /dev/null
+++ b/Tests/RunCMake/CPack/RPM/DEPENDENCIES-ExpectedFiles.cmake
@@ -0,0 +1,13 @@
+set(whitespaces_ "[\t\n\r ]*")
+
+set(EXPECTED_FILES_COUNT "5")
+set(EXPECTED_FILE_1 "dependencies*-applications.rpm")
+set(EXPECTED_FILE_CONTENT_1 "^/usr/foo${whitespaces_}/usr/foo/test_prog$")
+set(EXPECTED_FILE_2 "dependencies*-applications_auto.rpm")
+set(EXPECTED_FILE_CONTENT_2 "^/usr/foo_auto${whitespaces_}/usr/foo_auto/test_prog$")
+set(EXPECTED_FILE_3 "dependencies*-headers.rpm")
+set(EXPECTED_FILE_CONTENT_3 "^/usr/bar${whitespaces_}/usr/bar/CMakeLists.txt$")
+set(EXPECTED_FILE_4 "dependencies*-libs.rpm")
+set(EXPECTED_FILE_CONTENT_4 "^/usr/bas${whitespaces_}/usr/bas/libtest_lib.so$")
+set(EXPECTED_FILE_5 "dependencies*-libs_auto.rpm")
+set(EXPECTED_FILE_CONTENT_5 "^/usr/bas_auto${whitespaces_}/usr/bas_auto/libtest_lib.so$")
diff --git a/Tests/RunCMake/CPack/RPM/DEPENDENCIES-VerifyResult.cmake b/Tests/RunCMake/CPack/RPM/DEPENDENCIES-VerifyResult.cmake
new file mode 100644
index 0000000..fec8889
--- /dev/null
+++ b/Tests/RunCMake/CPack/RPM/DEPENDENCIES-VerifyResult.cmake
@@ -0,0 +1,45 @@
+function(checkDependencies_ FILE TYPE COMPARE_LIST)
+ set(whitespaces_ "[\t\n\r ]*")
+
+ execute_process(COMMAND ${RPM_EXECUTABLE} -qp --${TYPE} ${FILE}
+ WORKING_DIRECTORY "${CPACK_TEMPORARY_DIRECTORY}"
+ OUTPUT_VARIABLE FILE_DEPENDENCIES_
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+ string(REPLACE "\n" ";" FILE_DEPENDENCIES_LIST_ "${FILE_DEPENDENCIES_}")
+
+ foreach(COMPARE_REGEX_ IN LISTS COMPARE_LIST)
+ unset(FOUND_)
+
+ foreach(COMPARE_ IN LISTS FILE_DEPENDENCIES_LIST_)
+ if(COMPARE_ MATCHES "${COMPARE_REGEX_}")
+ set(FOUND_ true)
+ break()
+ endif()
+ endforeach()
+
+ if(NOT FOUND_)
+ message(FATAL_ERROR "Missing dependencies in '${FILE}'; check type: '${TYPE}'; file info: '${FILE_DEPENDENCIES_}'; missing: '${COMPARE_REGEX_}'")
+ endif()
+ endforeach()
+endfunction()
+
+# TODO add tests for what should not be present in lists
+checkDependencies_("${FOUND_FILE_1}" "requires" "depend-application;depend-application-b")
+checkDependencies_("${FOUND_FILE_2}" "requires" "depend-application;depend-application-b;libtest_lib\\.so.*")
+checkDependencies_("${FOUND_FILE_3}" "requires" "depend-headers")
+checkDependencies_("${FOUND_FILE_4}" "requires" "depend-default;depend-default-b")
+checkDependencies_("${FOUND_FILE_5}" "requires" "depend-default;depend-default-b")
+
+checkDependencies_("${FOUND_FILE_1}" "conflicts" "conflict-application;conflict-application-b")
+checkDependencies_("${FOUND_FILE_2}" "conflicts" "conflict-application;conflict-application-b")
+checkDependencies_("${FOUND_FILE_3}" "conflicts" "conflict-headers")
+checkDependencies_("${FOUND_FILE_4}" "conflicts" "conflict-default;conflict-default-b")
+checkDependencies_("${FOUND_FILE_5}" "conflicts" "conflict-default;conflict-default-b")
+
+checkDependencies_("${FOUND_FILE_1}" "provides" "provided-default;provided-default-b")
+checkDependencies_("${FOUND_FILE_2}" "provides" "provided-default;provided-default-b")
+checkDependencies_("${FOUND_FILE_3}" "provides" "provided-default;provided-default-b")
+checkDependencies_("${FOUND_FILE_4}" "provides" "provided-lib")
+checkDependencies_("${FOUND_FILE_5}" "provides" "provided-lib_auto;provided-lib_auto-b")
diff --git a/Tests/RunCMake/CPack/RPM/DEPENDENCIES-specifics.cmake b/Tests/RunCMake/CPack/RPM/DEPENDENCIES-specifics.cmake
new file mode 100644
index 0000000..2cdfece
--- /dev/null
+++ b/Tests/RunCMake/CPack/RPM/DEPENDENCIES-specifics.cmake
@@ -0,0 +1,22 @@
+set(CPACK_RPM_COMPONENT_INSTALL "ON")
+
+# FIXME auto autoprov is not tested at the moment as Ubuntu 15.04 rpmbuild
+# does not use them correctly: https://bugs.launchpad.net/rpm/+bug/1475755
+set(CPACK_RPM_PACKAGE_AUTOREQ "no")
+set(CPACK_RPM_PACKAGE_AUTOPROV "no")
+set(CPACK_RPM_applications_auto_PACKAGE_AUTOREQPROV "yes")
+set(CPACK_RPM_libs_auto_PACKAGE_AUTOREQPROV "yes")
+
+set(CPACK_RPM_PACKAGE_REQUIRES "depend-default, depend-default-b")
+set(CPACK_RPM_applications_PACKAGE_REQUIRES "depend-application, depend-application-b")
+set(CPACK_RPM_applications_auto_PACKAGE_REQUIRES "depend-application, depend-application-b")
+set(CPACK_RPM_headers_PACKAGE_REQUIRES "depend-headers")
+
+set(CPACK_RPM_PACKAGE_CONFLICTS "conflict-default, conflict-default-b")
+set(CPACK_RPM_applications_PACKAGE_CONFLICTS "conflict-application, conflict-application-b")
+set(CPACK_RPM_applications_auto_PACKAGE_CONFLICTS "conflict-application, conflict-application-b")
+set(CPACK_RPM_headers_PACKAGE_CONFLICTS "conflict-headers")
+
+set(CPACK_RPM_PACKAGE_PROVIDES "provided-default, provided-default-b")
+set(CPACK_RPM_libs_PACKAGE_PROVIDES "provided-lib")
+set(CPACK_RPM_libs_auto_PACKAGE_PROVIDES "provided-lib_auto, provided-lib_auto-b")
diff --git a/Tests/RunCMake/CPack/RunCMakeTest.cmake b/Tests/RunCMake/CPack/RunCMakeTest.cmake
index 97ef238..3e5714d 100644
--- a/Tests/RunCMake/CPack/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CPack/RunCMakeTest.cmake
@@ -7,3 +7,4 @@ include("${RunCMake_SOURCE_DIR}/CPackTestHelpers.cmake")
run_cpack_test(MINIMAL "RPM;DEB" false)
run_cpack_test(PARTIALLY_RELOCATABLE_WARNING "RPM" false)
run_cpack_test(DEB_EXTRA "DEB" false)
+run_cpack_test(DEPENDENCIES "RPM;DEB" true)
diff --git a/Tests/RunCMake/CPack/VerifyResult.cmake b/Tests/RunCMake/CPack/VerifyResult.cmake
index e059d9c..96efa9e 100644
--- a/Tests/RunCMake/CPack/VerifyResult.cmake
+++ b/Tests/RunCMake/CPack/VerifyResult.cmake
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
+cmake_minimum_required(VERSION ${CMAKE_VERSION} FATAL_ERROR)
include("${config_file}")
include("${src_dir}/${GENERATOR_TYPE}/Helpers.cmake")
diff --git a/Tests/RunCMake/CompilerNotFound/BadCompilerC-stderr-JOM.txt b/Tests/RunCMake/CompilerNotFound/BadCompilerC-stderr-JOM.txt
new file mode 100644
index 0000000..b7db7eb
--- /dev/null
+++ b/Tests/RunCMake/CompilerNotFound/BadCompilerC-stderr-JOM.txt
@@ -0,0 +1,17 @@
+CMake Error at BadCompilerC.cmake:2 \(enable_language\):
+ The CMAKE_C_COMPILER:
+
+ no-C-compiler
+
+ is not a full path and was not found in the PATH.
+
+ To use the JOM generator with Visual C\+\+, cmake must be run from a shell
+ that can use the compiler cl from the command line. This environment is
+ unable to invoke the cl compiler. To fix this problem, run cmake from the
+ Visual Studio Command Prompt \(vcvarsall.bat\).
+
+ Tell CMake where to find the compiler by setting either the environment
+ variable "CC" or the CMake cache entry CMAKE_C_COMPILER to the full path to
+ the compiler, or to the compiler name if it is in the PATH.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/CompilerNotFound/BadCompilerC-stderr-NMake.txt b/Tests/RunCMake/CompilerNotFound/BadCompilerC-stderr-NMake.txt
new file mode 100644
index 0000000..03c5933
--- /dev/null
+++ b/Tests/RunCMake/CompilerNotFound/BadCompilerC-stderr-NMake.txt
@@ -0,0 +1,17 @@
+CMake Error at BadCompilerC.cmake:2 \(enable_language\):
+ The CMAKE_C_COMPILER:
+
+ no-C-compiler
+
+ is not a full path and was not found in the PATH.
+
+ To use the NMake generator with Visual C\+\+, cmake must be run from a shell
+ that can use the compiler cl from the command line. This environment is
+ unable to invoke the cl compiler. To fix this problem, run cmake from the
+ Visual Studio Command Prompt \(vcvarsall.bat\).
+
+ Tell CMake where to find the compiler by setting either the environment
+ variable "CC" or the CMake cache entry CMAKE_C_COMPILER to the full path to
+ the compiler, or to the compiler name if it is in the PATH.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/CompilerNotFound/BadCompilerCXX-stderr-JOM.txt b/Tests/RunCMake/CompilerNotFound/BadCompilerCXX-stderr-JOM.txt
new file mode 100644
index 0000000..4b42ea6
--- /dev/null
+++ b/Tests/RunCMake/CompilerNotFound/BadCompilerCXX-stderr-JOM.txt
@@ -0,0 +1,17 @@
+CMake Error at BadCompilerCXX.cmake:2 \(enable_language\):
+ The CMAKE_CXX_COMPILER:
+
+ no-CXX-compiler
+
+ is not a full path and was not found in the PATH.
+
+ To use the JOM generator with Visual C\+\+, cmake must be run from a shell
+ that can use the compiler cl from the command line. This environment is
+ unable to invoke the cl compiler. To fix this problem, run cmake from the
+ Visual Studio Command Prompt \(vcvarsall.bat\).
+
+ Tell CMake where to find the compiler by setting either the environment
+ variable "CXX" or the CMake cache entry CMAKE_CXX_COMPILER to the full path
+ to the compiler, or to the compiler name if it is in the PATH.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/CompilerNotFound/BadCompilerCXX-stderr-NMake.txt b/Tests/RunCMake/CompilerNotFound/BadCompilerCXX-stderr-NMake.txt
new file mode 100644
index 0000000..1bfcdcc
--- /dev/null
+++ b/Tests/RunCMake/CompilerNotFound/BadCompilerCXX-stderr-NMake.txt
@@ -0,0 +1,17 @@
+CMake Error at BadCompilerCXX.cmake:2 \(enable_language\):
+ The CMAKE_CXX_COMPILER:
+
+ no-CXX-compiler
+
+ is not a full path and was not found in the PATH.
+
+ To use the NMake generator with Visual C\+\+, cmake must be run from a shell
+ that can use the compiler cl from the command line. This environment is
+ unable to invoke the cl compiler. To fix this problem, run cmake from the
+ Visual Studio Command Prompt \(vcvarsall.bat\).
+
+ Tell CMake where to find the compiler by setting either the environment
+ variable "CXX" or the CMake cache entry CMAKE_CXX_COMPILER to the full path
+ to the compiler, or to the compiler name if it is in the PATH.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/CompilerNotFound/BadCompilerCandCXX-stderr-JOM.txt b/Tests/RunCMake/CompilerNotFound/BadCompilerCandCXX-stderr-JOM.txt
new file mode 100644
index 0000000..f25a267
--- /dev/null
+++ b/Tests/RunCMake/CompilerNotFound/BadCompilerCandCXX-stderr-JOM.txt
@@ -0,0 +1,35 @@
+CMake Error at BadCompilerCandCXX.cmake:3 \(project\):
+ The CMAKE_C_COMPILER:
+
+ no-C-compiler
+
+ is not a full path and was not found in the PATH.
+
+ To use the JOM generator with Visual C\+\+, cmake must be run from a shell
+ that can use the compiler cl from the command line. This environment is
+ unable to invoke the cl compiler. To fix this problem, run cmake from the
+ Visual Studio Command Prompt \(vcvarsall.bat\).
+
+ Tell CMake where to find the compiler by setting either the environment
+ variable "CC" or the CMake cache entry CMAKE_C_COMPILER to the full path to
+ the compiler, or to the compiler name if it is in the PATH.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
++
+CMake Error at BadCompilerCandCXX.cmake:3 \(project\):
+ The CMAKE_CXX_COMPILER:
+
+ no-CXX-compiler
+
+ is not a full path and was not found in the PATH.
+
+ To use the JOM generator with Visual C\+\+, cmake must be run from a shell
+ that can use the compiler cl from the command line. This environment is
+ unable to invoke the cl compiler. To fix this problem, run cmake from the
+ Visual Studio Command Prompt \(vcvarsall.bat\).
+
+ Tell CMake where to find the compiler by setting either the environment
+ variable "CXX" or the CMake cache entry CMAKE_CXX_COMPILER to the full path
+ to the compiler, or to the compiler name if it is in the PATH.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/CompilerNotFound/BadCompilerCandCXX-stderr-NMake.txt b/Tests/RunCMake/CompilerNotFound/BadCompilerCandCXX-stderr-NMake.txt
new file mode 100644
index 0000000..ffcdce8
--- /dev/null
+++ b/Tests/RunCMake/CompilerNotFound/BadCompilerCandCXX-stderr-NMake.txt
@@ -0,0 +1,35 @@
+CMake Error at BadCompilerCandCXX.cmake:3 \(project\):
+ The CMAKE_C_COMPILER:
+
+ no-C-compiler
+
+ is not a full path and was not found in the PATH.
+
+ To use the NMake generator with Visual C\+\+, cmake must be run from a shell
+ that can use the compiler cl from the command line. This environment is
+ unable to invoke the cl compiler. To fix this problem, run cmake from the
+ Visual Studio Command Prompt \(vcvarsall.bat\).
+
+ Tell CMake where to find the compiler by setting either the environment
+ variable "CC" or the CMake cache entry CMAKE_C_COMPILER to the full path to
+ the compiler, or to the compiler name if it is in the PATH.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
++
+CMake Error at BadCompilerCandCXX.cmake:3 \(project\):
+ The CMAKE_CXX_COMPILER:
+
+ no-CXX-compiler
+
+ is not a full path and was not found in the PATH.
+
+ To use the NMake generator with Visual C\+\+, cmake must be run from a shell
+ that can use the compiler cl from the command line. This environment is
+ unable to invoke the cl compiler. To fix this problem, run cmake from the
+ Visual Studio Command Prompt \(vcvarsall.bat\).
+
+ Tell CMake where to find the compiler by setting either the environment
+ variable "CXX" or the CMake cache entry CMAKE_CXX_COMPILER to the full path
+ to the compiler, or to the compiler name if it is in the PATH.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/CompilerNotFound/RunCMakeTest.cmake b/Tests/RunCMake/CompilerNotFound/RunCMakeTest.cmake
index 8b84f39..19d149c 100644
--- a/Tests/RunCMake/CompilerNotFound/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CompilerNotFound/RunCMakeTest.cmake
@@ -4,6 +4,20 @@ if("${RunCMake_GENERATOR}" MATCHES "Visual Studio|Xcode")
run_cmake(NoCompilerC-IDE)
run_cmake(NoCompilerCXX-IDE)
run_cmake(NoCompilerCandCXX-IDE)
+elseif(RunCMake_GENERATOR STREQUAL "NMake Makefiles")
+ set(RunCMake-stderr-file BadCompilerC-stderr-NMake.txt)
+ run_cmake(BadCompilerC)
+ set(RunCMake-stderr-file BadCompilerCXX-stderr-NMake.txt)
+ run_cmake(BadCompilerCXX)
+ set(RunCMake-stderr-file BadCompilerCandCXX-stderr-NMake.txt)
+ run_cmake(BadCompilerCandCXX)
+elseif(RunCMake_GENERATOR STREQUAL "NMake Makefiles JOM")
+ set(RunCMake-stderr-file BadCompilerC-stderr-JOM.txt)
+ run_cmake(BadCompilerC)
+ set(RunCMake-stderr-file BadCompilerCXX-stderr-JOM.txt)
+ run_cmake(BadCompilerCXX)
+ set(RunCMake-stderr-file BadCompilerCandCXX-stderr-JOM.txt)
+ run_cmake(BadCompilerCandCXX)
else()
run_cmake(BadCompilerC)
run_cmake(BadCompilerCXX)
diff --git a/Tests/RunCMake/GeneratorExpression/ImportedTarget-TARGET_PDB_FILE-result.txt b/Tests/RunCMake/GeneratorExpression/ImportedTarget-TARGET_PDB_FILE-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/ImportedTarget-TARGET_PDB_FILE-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GeneratorExpression/ImportedTarget-TARGET_PDB_FILE-stderr.txt b/Tests/RunCMake/GeneratorExpression/ImportedTarget-TARGET_PDB_FILE-stderr.txt
new file mode 100644
index 0000000..d915ecb
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/ImportedTarget-TARGET_PDB_FILE-stderr.txt
@@ -0,0 +1,8 @@
+CMake Error at ImportedTarget-TARGET_PDB_FILE.cmake:2 \(add_custom_target\):
+ Error evaluating generator expression:
+
+ \$<TARGET_PDB_FILE:empty>
+
+ TARGET_PDB_FILE not allowed for IMPORTED targets.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/GeneratorExpression/ImportedTarget-TARGET_PDB_FILE.cmake b/Tests/RunCMake/GeneratorExpression/ImportedTarget-TARGET_PDB_FILE.cmake
new file mode 100644
index 0000000..c55c5d5
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/ImportedTarget-TARGET_PDB_FILE.cmake
@@ -0,0 +1,2 @@
+add_library(empty UNKNOWN IMPORTED)
+add_custom_target(custom COMMAND echo $<TARGET_PDB_FILE:empty>)
diff --git a/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake b/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake
index 1c8fab5..21fc851 100644
--- a/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake
+++ b/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake
@@ -25,7 +25,9 @@ run_cmake(COMPILE_LANGUAGE-add_executable)
run_cmake(COMPILE_LANGUAGE-add_library)
run_cmake(COMPILE_LANGUAGE-add_test)
run_cmake(COMPILE_LANGUAGE-unknown-lang)
+run_cmake(TARGET_FILE-recursion)
+run_cmake(ImportedTarget-TARGET_PDB_FILE)
if(LINKER_SUPPORTS_PDB)
run_cmake(NonValidTarget-TARGET_PDB_FILE)
run_cmake(ValidTarget-TARGET_PDB_FILE)
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_FILE-recursion-result.txt b/Tests/RunCMake/GeneratorExpression/TARGET_FILE-recursion-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_FILE-recursion-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_FILE-recursion-stderr.txt b/Tests/RunCMake/GeneratorExpression/TARGET_FILE-recursion-stderr.txt
new file mode 100644
index 0000000..5b15526
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_FILE-recursion-stderr.txt
@@ -0,0 +1,4 @@
+CMake Error at TARGET_FILE-recursion.cmake:[0-9]+ \(add_executable\):
+ Target 'empty1' OUTPUT_DIRECTORY depends on itself.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_FILE-recursion.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_FILE-recursion.cmake
new file mode 100644
index 0000000..7633be1
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_FILE-recursion.cmake
@@ -0,0 +1,3 @@
+enable_language(C)
+add_executable(empty1 empty.c)
+set_property(TARGET empty1 PROPERTY RUNTIME_OUTPUT_DIRECTORY $<TARGET_FILE_DIR:empty1>)
diff --git a/Tests/RunCMake/PolicyScope/CMakeLists.txt b/Tests/RunCMake/PolicyScope/CMakeLists.txt
new file mode 100644
index 0000000..667561e
--- /dev/null
+++ b/Tests/RunCMake/PolicyScope/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 2.8.12)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake NO_POLICY_SCOPE)
diff --git a/Tests/RunCMake/PolicyScope/RunCMakeTest.cmake b/Tests/RunCMake/PolicyScope/RunCMakeTest.cmake
new file mode 100644
index 0000000..d6c021f
--- /dev/null
+++ b/Tests/RunCMake/PolicyScope/RunCMakeTest.cmake
@@ -0,0 +1,4 @@
+include(RunCMake)
+
+run_cmake(parent-dir-generate-time)
+run_cmake(dir-in-macro-generate-time)
diff --git a/Tests/RunCMake/PolicyScope/dir-in-macro-generate-time-result.txt b/Tests/RunCMake/PolicyScope/dir-in-macro-generate-time-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/PolicyScope/dir-in-macro-generate-time-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/PolicyScope/dir-in-macro-generate-time-stderr.txt b/Tests/RunCMake/PolicyScope/dir-in-macro-generate-time-stderr.txt
new file mode 100644
index 0000000..d223f42
--- /dev/null
+++ b/Tests/RunCMake/PolicyScope/dir-in-macro-generate-time-stderr.txt
@@ -0,0 +1,5 @@
+CMake Warning \(dev\) at dir1/CMakeLists.txt:5 \(target_compile_definitions\):
+ Policy CMP0044 is not set: Case sensitive <LANG>_COMPILER_ID generator
+ expressions. Run "cmake --help-policy CMP0044" for policy details. Use
+ the cmake_policy command to set the policy and suppress this warning.
+This warning is for project developers. Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/PolicyScope/dir-in-macro-generate-time.cmake b/Tests/RunCMake/PolicyScope/dir-in-macro-generate-time.cmake
new file mode 100644
index 0000000..04a7c2c
--- /dev/null
+++ b/Tests/RunCMake/PolicyScope/dir-in-macro-generate-time.cmake
@@ -0,0 +1,2 @@
+
+include(dir-in-macro-include.cmake)
diff --git a/Tests/RunCMake/PolicyScope/dir-in-macro-include.cmake b/Tests/RunCMake/PolicyScope/dir-in-macro-include.cmake
new file mode 100644
index 0000000..fd326f1
--- /dev/null
+++ b/Tests/RunCMake/PolicyScope/dir-in-macro-include.cmake
@@ -0,0 +1,6 @@
+
+enable_language(CXX)
+
+# This does not affect dir1 despite being set before the add_subdirectory.
+cmake_policy(SET CMP0044 NEW)
+add_subdirectory(dir1)
diff --git a/Tests/RunCMake/PolicyScope/dir1/CMakeLists.txt b/Tests/RunCMake/PolicyScope/dir1/CMakeLists.txt
new file mode 100644
index 0000000..16bcb36
--- /dev/null
+++ b/Tests/RunCMake/PolicyScope/dir1/CMakeLists.txt
@@ -0,0 +1,5 @@
+
+
+add_library(foo STATIC foo.cpp)
+string(TOLOWER ${CMAKE_CXX_COMPILER_ID} compiler_id)
+target_compile_definitions(foo PRIVATE Foo=$<CXX_COMPILER_ID:${compiler_id}>)
diff --git a/Tests/RunCMake/PolicyScope/dir1/foo.cpp b/Tests/RunCMake/PolicyScope/dir1/foo.cpp
new file mode 100644
index 0000000..766b775
--- /dev/null
+++ b/Tests/RunCMake/PolicyScope/dir1/foo.cpp
@@ -0,0 +1,5 @@
+
+int main()
+{
+ return 0;
+}
diff --git a/Tests/RunCMake/PolicyScope/parent-dir-generate-time-result.txt b/Tests/RunCMake/PolicyScope/parent-dir-generate-time-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/PolicyScope/parent-dir-generate-time-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/PolicyScope/parent-dir-generate-time.cmake b/Tests/RunCMake/PolicyScope/parent-dir-generate-time.cmake
new file mode 100644
index 0000000..a0842f7
--- /dev/null
+++ b/Tests/RunCMake/PolicyScope/parent-dir-generate-time.cmake
@@ -0,0 +1,7 @@
+
+enable_language(CXX)
+
+add_subdirectory(dir1)
+
+# This affects dir1 despite being set after the add_subdirectory.
+cmake_policy(SET CMP0044 NEW)
diff --git a/Tests/RunCMake/add_subdirectory/CMakeLists.txt b/Tests/RunCMake/add_subdirectory/CMakeLists.txt
new file mode 100644
index 0000000..18dfd26
--- /dev/null
+++ b/Tests/RunCMake/add_subdirectory/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.2)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/add_subdirectory/DoesNotExist-result.txt b/Tests/RunCMake/add_subdirectory/DoesNotExist-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/add_subdirectory/DoesNotExist-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/add_subdirectory/DoesNotExist-stderr.txt b/Tests/RunCMake/add_subdirectory/DoesNotExist-stderr.txt
new file mode 100644
index 0000000..369a956
--- /dev/null
+++ b/Tests/RunCMake/add_subdirectory/DoesNotExist-stderr.txt
@@ -0,0 +1,5 @@
+^CMake Error at DoesNotExist.cmake:1 \(add_subdirectory\):
+ add_subdirectory given source "DoesNotExist" which is not an existing
+ directory.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/add_subdirectory/DoesNotExist.cmake b/Tests/RunCMake/add_subdirectory/DoesNotExist.cmake
new file mode 100644
index 0000000..fe2945c
--- /dev/null
+++ b/Tests/RunCMake/add_subdirectory/DoesNotExist.cmake
@@ -0,0 +1 @@
+add_subdirectory(DoesNotExist)
diff --git a/Tests/RunCMake/add_subdirectory/Missing-result.txt b/Tests/RunCMake/add_subdirectory/Missing-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/add_subdirectory/Missing-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/add_subdirectory/Missing-stderr.txt b/Tests/RunCMake/add_subdirectory/Missing-stderr.txt
new file mode 100644
index 0000000..aba0675
--- /dev/null
+++ b/Tests/RunCMake/add_subdirectory/Missing-stderr.txt
@@ -0,0 +1,8 @@
+^CMake Error at Missing.cmake:1 \(add_subdirectory\):
+ The source directory
+
+ .*/Tests/RunCMake/add_subdirectory/Missing
+
+ does not contain a CMakeLists.txt file.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/add_subdirectory/Missing.cmake b/Tests/RunCMake/add_subdirectory/Missing.cmake
new file mode 100644
index 0000000..0e68927
--- /dev/null
+++ b/Tests/RunCMake/add_subdirectory/Missing.cmake
@@ -0,0 +1 @@
+add_subdirectory(Missing)
diff --git a/Tests/RunCMake/add_subdirectory/Missing/Missing.txt b/Tests/RunCMake/add_subdirectory/Missing/Missing.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/add_subdirectory/Missing/Missing.txt
diff --git a/Tests/RunCMake/add_subdirectory/RunCMakeTest.cmake b/Tests/RunCMake/add_subdirectory/RunCMakeTest.cmake
new file mode 100644
index 0000000..a3ddec8
--- /dev/null
+++ b/Tests/RunCMake/add_subdirectory/RunCMakeTest.cmake
@@ -0,0 +1,4 @@
+include(RunCMake)
+
+run_cmake(DoesNotExist)
+run_cmake(Missing)
diff --git a/Tests/RunCMake/get_filename_component/CMakeLists.txt b/Tests/RunCMake/get_filename_component/CMakeLists.txt
index 12cd3c7..74b3ff8 100644
--- a/Tests/RunCMake/get_filename_component/CMakeLists.txt
+++ b/Tests/RunCMake/get_filename_component/CMakeLists.txt
@@ -1,3 +1,3 @@
-cmake_minimum_required(VERSION 2.8.4)
+cmake_minimum_required(VERSION 3.3)
project(${RunCMake_TEST} NONE)
include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/get_filename_component/KnownComponents.cmake b/Tests/RunCMake/get_filename_component/KnownComponents.cmake
index 9d7cf90..386109f 100644
--- a/Tests/RunCMake/get_filename_component/KnownComponents.cmake
+++ b/Tests/RunCMake/get_filename_component/KnownComponents.cmake
@@ -1,9 +1,11 @@
+# Assertion macro
macro(check desc actual expect)
if(NOT "x${actual}" STREQUAL "x${expect}")
message(SEND_ERROR "${desc}: got \"${actual}\", not \"${expect}\"")
endif()
endmacro()
+# General test of all component types given an absolute path.
set(filename "/path/to/filename.ext.in")
set(expect_DIRECTORY "/path/to")
set(expect_NAME "filename.ext.in")
@@ -13,14 +15,19 @@ set(expect_PATH "/path/to")
foreach(c DIRECTORY NAME EXT NAME_WE PATH)
get_filename_component(actual_${c} "${filename}" ${c})
check("${c}" "${actual_${c}}" "${expect_${c}}")
+ list(APPEND non_cache_vars actual_${c})
endforeach()
+# Test Windows paths with DIRECTORY component and an absolute Windows path.
get_filename_component(test_slashes "c:\\path\\to\\filename.ext.in" DIRECTORY)
check("DIRECTORY from backslashes" "${test_slashes}" "c:/path/to")
+list(APPEND non_cache_vars test_slashes)
get_filename_component(test_winroot "c:\\filename.ext.in" DIRECTORY)
check("DIRECTORY in windows root" "${test_winroot}" "c:/")
+list(APPEND non_cache_vars test_winroot)
+# Test finding absolute paths.
get_filename_component(test_absolute "/path/to/a/../filename.ext.in" ABSOLUTE)
check("ABSOLUTE" "${test_absolute}" "/path/to/filename.ext.in")
@@ -29,10 +36,80 @@ check("ABSOLUTE .. in root" "${test_absolute}" "/path/to/filename.ext.in")
get_filename_component(test_absolute "c:/../path/to/filename.ext.in" ABSOLUTE)
check("ABSOLUTE .. in windows root" "${test_absolute}" "c:/path/to/filename.ext.in")
+list(APPEND non_cache_vars test_absolute)
+
+# Test the PROGRAM component type.
+get_filename_component(test_program_name "/ arg1 arg2" PROGRAM)
+check("PROGRAM with no args output" "${test_program_name}" "/")
+
+get_filename_component(test_program_name "/ arg1 arg2" PROGRAM
+ PROGRAM_ARGS test_program_args)
+check("PROGRAM with args output: name" "${test_program_name}" "/")
+check("PROGRAM with args output: args" "${test_program_args}" " arg1 arg2")
+
+list(APPEND non_cache_vars test_program_name)
+list(APPEND non_cache_vars test_program_args)
+
+# Test CACHE parameter for most component types.
get_filename_component(test_cache "/path/to/filename.ext.in" DIRECTORY CACHE)
check("CACHE 1" "${test_cache}" "/path/to")
+# Make sure that the existing CACHE entry from previous is honored:
get_filename_component(test_cache "/path/to/other/filename.ext.in" DIRECTORY CACHE)
check("CACHE 2" "${test_cache}" "/path/to")
unset(test_cache CACHE)
get_filename_component(test_cache "/path/to/other/filename.ext.in" DIRECTORY CACHE)
check("CACHE 3" "${test_cache}" "/path/to/other")
+
+list(APPEND cache_vars test_cache)
+
+# Test the PROGRAM component type with CACHE specified.
+
+# 1. Make sure it makes a cache variable in the first place for basic usage:
+get_filename_component(test_cache_program_name_1 "/ arg1 arg2" PROGRAM CACHE)
+check("PROGRAM CACHE 1 with no args output" "${test_cache_program_name_1}" "/")
+list(APPEND cache_vars test_cache_program_name_1)
+
+# 2. Set some existing cache variables & make sure the function returns them:
+set(test_cache_program_name_2 DummyProgramName CACHE FILEPATH "")
+get_filename_component(test_cache_program_name_2 "/ arg1 arg2" PROGRAM CACHE)
+check("PROGRAM CACHE 2 with no args output" "${test_cache_program_name_2}"
+ "DummyProgramName")
+list(APPEND cache_vars test_cache_program_name_2)
+
+# 3. Now test basic usage when PROGRAM_ARGS is used:
+get_filename_component(test_cache_program_name_3 "/ arg1 arg2" PROGRAM
+ PROGRAM_ARGS test_cache_program_args_3 CACHE)
+check("PROGRAM CACHE 3 name" "${test_cache_program_name_3}" "/")
+check("PROGRAM CACHE 3 args" "${test_cache_program_args_3}" " arg1 arg2")
+list(APPEND cache_vars test_cache_program_name_3)
+list(APPEND cache_vars test_cache_program_args_3)
+
+# 4. Test that existing cache variables are returned when PROGRAM_ARGS is used:
+set(test_cache_program_name_4 DummyPgm CACHE FILEPATH "")
+set(test_cache_program_args_4 DummyArgs CACHE STRING "")
+get_filename_component(test_cache_program_name_4 "/ arg1 arg2" PROGRAM
+ PROGRAM_ARGS test_cache_program_args_4 CACHE)
+check("PROGRAM CACHE 4 name" "${test_cache_program_name_4}" "DummyPgm")
+check("PROGRAM CACHE 4 args" "${test_cache_program_args_4}" "DummyArgs")
+list(APPEND cache_vars test_cache_program_name_4)
+list(APPEND cache_vars test_cache_program_name_4)
+
+# Test that ONLY the expected cache variables were created.
+get_cmake_property(current_cache_vars CACHE_VARIABLES)
+get_cmake_property(current_vars VARIABLES)
+
+foreach(thisVar ${cache_vars})
+ if(NOT thisVar IN_LIST current_cache_vars)
+ message(SEND_ERROR "${thisVar} expected in cache but was not found.")
+ endif()
+endforeach()
+
+foreach(thisVar ${non_cache_vars})
+ if(thisVar IN_LIST current_cache_vars)
+ message(SEND_ERROR "${thisVar} unexpectedly found in cache.")
+ endif()
+ if(NOT thisVar IN_LIST current_vars)
+ # Catch likely typo when appending to non_cache_vars:
+ message(SEND_ERROR "${thisVar} not found in regular variable list.")
+ endif()
+endforeach()
diff --git a/Tests/RunCMake/if/RunCMakeTest.cmake b/Tests/RunCMake/if/RunCMakeTest.cmake
index 2c0c4d7..3f4d2a2 100644
--- a/Tests/RunCMake/if/RunCMakeTest.cmake
+++ b/Tests/RunCMake/if/RunCMakeTest.cmake
@@ -4,3 +4,6 @@ run_cmake(InvalidArgument1)
run_cmake(IsDirectory)
run_cmake(IsDirectoryLong)
run_cmake(elseif-message)
+
+run_cmake(TestNameThatExists)
+run_cmake(TestNameThatDoesNotExist)
diff --git a/Tests/RunCMake/if/TestNameThatDoesNotExist-stdout.txt b/Tests/RunCMake/if/TestNameThatDoesNotExist-stdout.txt
new file mode 100644
index 0000000..8874ca8
--- /dev/null
+++ b/Tests/RunCMake/if/TestNameThatDoesNotExist-stdout.txt
@@ -0,0 +1 @@
+TestThatDoesNotExist is false
diff --git a/Tests/RunCMake/if/TestNameThatDoesNotExist.cmake b/Tests/RunCMake/if/TestNameThatDoesNotExist.cmake
new file mode 100644
index 0000000..74bc8b0
--- /dev/null
+++ b/Tests/RunCMake/if/TestNameThatDoesNotExist.cmake
@@ -0,0 +1,6 @@
+cmake_policy(SET CMP0064 NEW)
+if(TEST TestThatDoesNotExist)
+ message(FATAL_ERROR "if TestThatDoesNotExist is true")
+else()
+ message(STATUS "if TestThatDoesNotExist is false")
+endif()
diff --git a/Tests/RunCMake/if/TestNameThatExists-stdout.txt b/Tests/RunCMake/if/TestNameThatExists-stdout.txt
new file mode 100644
index 0000000..54911bc
--- /dev/null
+++ b/Tests/RunCMake/if/TestNameThatExists-stdout.txt
@@ -0,0 +1 @@
+TestThatExists is true
diff --git a/Tests/RunCMake/if/TestNameThatExists.cmake b/Tests/RunCMake/if/TestNameThatExists.cmake
new file mode 100644
index 0000000..65c2b46
--- /dev/null
+++ b/Tests/RunCMake/if/TestNameThatExists.cmake
@@ -0,0 +1,7 @@
+cmake_policy(SET CMP0064 NEW)
+add_test(NAME TestThatExists COMMAND ${CMAKE_COMMAND} -E echo "A CMake Test")
+if(TEST TestThatExists)
+ message(STATUS "if TestThatExists is true")
+else()
+ message(FATAL_ERROR "if TestThatExists is false")
+endif()
diff --git a/Tests/RunCMake/set_property/LINK_SEARCH_STATIC.cmake b/Tests/RunCMake/set_property/LINK_SEARCH_STATIC.cmake
new file mode 100644
index 0000000..70d2fee
--- /dev/null
+++ b/Tests/RunCMake/set_property/LINK_SEARCH_STATIC.cmake
@@ -0,0 +1,73 @@
+project(LinkSearchStatic)
+
+set(CMAKE_LINK_SEARCH_START_STATIC ON)
+add_executable(LinkSearchStartStaticInit1 LinkStatic.c)
+get_target_property(LSSS LinkSearchStartStaticInit1
+ LINK_SEARCH_START_STATIC)
+if(NOT LSSS)
+ message(FATAL_ERROR "Failed to correctly initialize LINK_SEARCH_START_STATIC")
+endif()
+unset(CMAKE_LINK_SEARCH_START_STATIC)
+
+add_executable(LinkSearchStartStaticSet1 LinkStatic.c)
+set_target_properties(LinkSearchStartStaticSet1 PROPERTIES
+ LINK_SEARCH_START_STATIC ON)
+get_target_property(LSSS LinkSearchStartStaticSet1
+ LINK_SEARCH_START_STATIC)
+if(NOT LSSS)
+ message(FATAL_ERROR "Failed to correctly set LINK_SEARCH_START_STATIC")
+endif()
+
+set(CMAKE_LINK_SEARCH_START_STATIC OFF)
+add_executable(LinkSearchStartStaticInit2 LinkStatic.c)
+get_target_property(LSSS LinkSearchStartStaticInit2
+ LINK_SEARCH_START_STATIC)
+if(LSSS)
+ message(FATAL_ERROR "Failed to correctly initialize LINK_SEARCH_START_STATIC")
+endif()
+unset(CMAKE_LINK_SEARCH_START_STATIC)
+
+add_executable(LinkSearchStartStaticSet2 LinkStatic.c)
+set_target_properties(LinkSearchStartStaticSet2 PROPERTIES
+ LINK_SEARCH_START_STATIC OFF)
+get_target_property(LSSS LinkSearchStartStaticSet2
+ LINK_SEARCH_START_STATIC)
+if(LSSS)
+ message(FATAL_ERROR "Failed to correctly set LINK_SEARCH_START_STATIC")
+endif()
+
+set(CMAKE_LINK_SEARCH_END_STATIC ON)
+add_executable(LinkSearchEndStaticInit1 LinkStatic.c)
+get_target_property(LSES LinkSearchEndStaticInit1
+ LINK_SEARCH_END_STATIC)
+if(NOT LSES)
+ message(FATAL_ERROR "Failed to correctly initialize LINK_SEARCH_END_STATIC")
+endif()
+unset(CMAKE_LINK_SEARCH_END_STATIC)
+
+add_executable(LinkSearchEndStaticSet1 LinkStatic.c)
+set_target_properties(LinkSearchEndStaticSet1 PROPERTIES
+ LINK_SEARCH_END_STATIC ON)
+get_target_property(LSSS LinkSearchEndStaticSet1
+ LINK_SEARCH_END_STATIC)
+if(NOT LSSS)
+ message(FATAL_ERROR "Failed to correctly set LINK_SEARCH_END_STATIC")
+endif()
+
+set(CMAKE_LINK_SEARCH_END_STATIC OFF)
+add_executable(LinkSearchEndStaticInit2 LinkStatic.c)
+get_target_property(LSES LinkSearchEndStaticInit2
+ LINK_SEARCH_END_STATIC)
+if(LSES)
+ message(FATAL_ERROR "Failed to correctly initialize LINK_SEARCH_END_STATIC")
+endif()
+unset(CMAKE_LINK_SEARCH_END_STATIC)
+
+add_executable(LinkSearchEndStaticSet2 LinkStatic.c)
+set_target_properties(LinkSearchEndStaticSet2 PROPERTIES
+ LINK_SEARCH_END_STATIC ON)
+get_target_property(LSSS LinkSearchEndStaticSet2
+ LINK_SEARCH_END_STATIC)
+if(NOT LSSS)
+ message(FATAL_ERROR "Failed to correctly set LINK_SEARCH_END_STATIC")
+endif()
diff --git a/Tests/RunCMake/set_property/LinkStatic.c b/Tests/RunCMake/set_property/LinkStatic.c
new file mode 100644
index 0000000..3600977
--- /dev/null
+++ b/Tests/RunCMake/set_property/LinkStatic.c
@@ -0,0 +1,5 @@
+#include <math.h>
+int main(void)
+{
+ return (int)sin(0);
+}
diff --git a/Tests/RunCMake/set_property/RunCMakeTest.cmake b/Tests/RunCMake/set_property/RunCMakeTest.cmake
index 54e63f7..ada8804 100644
--- a/Tests/RunCMake/set_property/RunCMakeTest.cmake
+++ b/Tests/RunCMake/set_property/RunCMakeTest.cmake
@@ -1,3 +1,4 @@
include(RunCMake)
run_cmake(LINK_LIBRARIES)
+run_cmake(LINK_SEARCH_STATIC)
diff --git a/Tests/RunCMake/target_link_libraries/RunCMakeTest.cmake b/Tests/RunCMake/target_link_libraries/RunCMakeTest.cmake
index 533c6a1..8307607 100644
--- a/Tests/RunCMake/target_link_libraries/RunCMakeTest.cmake
+++ b/Tests/RunCMake/target_link_libraries/RunCMakeTest.cmake
@@ -7,3 +7,4 @@ run_cmake(CMP0023-NEW-2)
run_cmake(MixedSignature)
run_cmake(Separate-PRIVATE-LINK_PRIVATE-uses)
run_cmake(SubDirTarget)
+run_cmake(SharedDepNotTarget)
diff --git a/Tests/RunCMake/target_link_libraries/SharedDepNotTarget.cmake b/Tests/RunCMake/target_link_libraries/SharedDepNotTarget.cmake
new file mode 100644
index 0000000..bab537e
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries/SharedDepNotTarget.cmake
@@ -0,0 +1,10 @@
+enable_language(C)
+set(CMAKE_LINK_DEPENDENT_LIBRARY_DIRS 1)
+set(CMAKE_SHARED_LIBRARY_SUFFIX ".so")
+add_library(imported SHARED IMPORTED)
+set_target_properties(imported PROPERTIES
+ IMPORTED_LOCATION "imported"
+ IMPORTED_LINK_DEPENDENT_LIBRARIES "/path/to/libSharedDep.so"
+ )
+add_executable(empty empty.c)
+target_link_libraries(empty imported)
diff --git a/Utilities/Release/dash2win64_cygwin.cmake b/Utilities/Release/dash2win64_cygwin.cmake
index ac3c527..d15915a 100644
--- a/Utilities/Release/dash2win64_cygwin.cmake
+++ b/Utilities/Release/dash2win64_cygwin.cmake
@@ -12,6 +12,7 @@ CTEST_TEST_TIMEOUT:STRING=7200
DART_TESTING_TIMEOUT:STRING=7200
SPHINX_HTML:BOOL=ON
SPHINX_MAN:BOOL=ON
+CMake_INSTALL_DEPENDENCIES:BOOL=ON
")
set(CXX g++)
set(CC gcc)
diff --git a/Utilities/Release/dash2win64_release.cmake b/Utilities/Release/dash2win64_release.cmake
index 2511db4..3ea895a 100644
--- a/Utilities/Release/dash2win64_release.cmake
+++ b/Utilities/Release/dash2win64_release.cmake
@@ -14,6 +14,7 @@ CMAKE_Fortran_COMPILER:FILEPATH=FALSE
CMAKE_GENERATOR:INTERNAL=Unix Makefiles
BUILD_QtDialog:BOOL:=TRUE
CMake_GUI_DISTRIBUTE_WITH_Qt_LGPL:BOOL=TRUE
+CMake_INSTALL_DEPENDENCIES:BOOL=ON
QT_QMAKE_EXECUTABLE:FILEPATH=c:/Dashboards/Support/qt-build/Qt/bin/qmake.exe
")
get_filename_component(path "${CMAKE_CURRENT_LIST_FILE}" PATH)
diff --git a/Utilities/Release/dashmacmini2_release.cmake b/Utilities/Release/dashmacmini2_release.cmake
index ba82aab..01f5b8b 100644
--- a/Utilities/Release/dashmacmini2_release.cmake
+++ b/Utilities/Release/dashmacmini2_release.cmake
@@ -18,6 +18,7 @@ CMAKE_SKIP_BOOTSTRAP_TEST:STRING=TRUE
CPACK_SYSTEM_NAME:STRING=Darwin-universal
BUILD_QtDialog:BOOL=TRUE
CMake_GUI_DISTRIBUTE_WITH_Qt_LGPL:BOOL=TRUE
+CMake_INSTALL_DEPENDENCIES:BOOL=ON
QT_QMAKE_EXECUTABLE:FILEPATH=/Users/kitware/Support/qt-4.8.0/install/bin/qmake
")
get_filename_component(path "${CMAKE_CURRENT_LIST_FILE}" PATH)
diff --git a/Utilities/Release/dashmacmini5_release.cmake b/Utilities/Release/dashmacmini5_release.cmake
index b407554..be1dfa9 100644
--- a/Utilities/Release/dashmacmini5_release.cmake
+++ b/Utilities/Release/dashmacmini5_release.cmake
@@ -20,6 +20,7 @@ CMAKE_SKIP_BOOTSTRAP_TEST:STRING=TRUE
CPACK_SYSTEM_NAME:STRING=Darwin-x86_64
BUILD_QtDialog:BOOL=TRUE
CMake_GUI_DISTRIBUTE_WITH_Qt_LGPL:BOOL=TRUE
+CMake_INSTALL_DEPENDENCIES:BOOL=ON
QT_QMAKE_EXECUTABLE:FILEPATH=/Users/kitware/Support/qt-4.8.6/install/bin/qmake
")
get_filename_component(path "${CMAKE_CURRENT_LIST_FILE}" PATH)
diff --git a/Utilities/Release/linux64_release.cmake b/Utilities/Release/linux64_release.cmake
index 2cd5dfc..25da00a 100644
--- a/Utilities/Release/linux64_release.cmake
+++ b/Utilities/Release/linux64_release.cmake
@@ -17,6 +17,7 @@ OPENSSL_SSL_LIBRARY:FILEPATH=/home/kitware/openssl-1.0.2d/lib/libssl.a
CPACK_SYSTEM_NAME:STRING=Linux-x86_64
BUILD_QtDialog:BOOL:=TRUE
CMake_GUI_DISTRIBUTE_WITH_Qt_LGPL:BOOL=TRUE
+CMake_INSTALL_DEPENDENCIES:BOOL=ON
QT_QMAKE_EXECUTABLE:FILEPATH=/home/kitware/qt-4.8.6/bin/qmake
")
get_filename_component(path "${CMAKE_CURRENT_LIST_FILE}" PATH)
diff --git a/Utilities/Release/magrathea_release.cmake b/Utilities/Release/magrathea_release.cmake
index b0e0a3a..b031eb8 100644
--- a/Utilities/Release/magrathea_release.cmake
+++ b/Utilities/Release/magrathea_release.cmake
@@ -17,6 +17,7 @@ OPENSSL_SSL_LIBRARY:FILEPATH=/home/kitware/openssl-1.0.2d/lib/libssl.a
CPACK_SYSTEM_NAME:STRING=Linux-i386
BUILD_QtDialog:BOOL:=TRUE
CMake_GUI_DISTRIBUTE_WITH_Qt_LGPL:BOOL=TRUE
+CMake_INSTALL_DEPENDENCIES:BOOL=ON
QT_QMAKE_EXECUTABLE:FILEPATH=/home/kitware/qt-4.43-install/bin/qmake
")
get_filename_component(path "${CMAKE_CURRENT_LIST_FILE}" PATH)
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..3c71232 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, &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..d12c73f 100644
--- a/Utilities/cmcurl/CMakeLists.txt
+++ b/Utilities/cmcurl/CMakeLists.txt
@@ -3,6 +3,7 @@ set(BUILD_CURL_EXE OFF CACHE INTERNAL "No curl exe")
set(BUILD_CURL_TESTS OFF CACHE INTERNAL "No curl tests")
set(BUILD_DASHBOARD_REPORTS OFF CACHE INTERNAL "No curl dashboard reports")
set(BUILD_RELEASE_DEBUG_DIRS OFF CACHE INTERNAL "No curl release/debug dirs")
+set(CMAKE_USE_GSSAPI OFF CACHE INTERNAL "Disable curl gssapi")
set(CMAKE_USE_LIBSSH2 OFF CACHE INTERNAL "Disable curl libssh2")
set(CMAKE_USE_OPENLDAP OFF CACHE INTERNAL "No curl OpenLDAP")
set(CURL_DISABLE_COOKIES OFF CACHE INTERNAL "Do not disable curl cookie support")
@@ -16,18 +17,24 @@ set(CURL_DISABLE_IMAP ON CACHE INTERNAL "Disable curl imap protocol?")
set(CURL_DISABLE_LDAP ON CACHE INTERNAL "Disable curl ldap protocol?")
set(CURL_DISABLE_LDAPS ON CACHE INTERNAL "Disable curl ldaps protocol?")
set(CURL_DISABLE_POP3 ON CACHE INTERNAL "Disable curl pop3 protocol?")
+set(CURL_DISABLE_PROXY OFF CACHE INTERNAL "Do not disable curl proxy")
set(CURL_DISABLE_RTSP ON CACHE INTERNAL "Disable curl rtsp protocol?")
set(CURL_DISABLE_SMTP ON CACHE INTERNAL "Disable curl smtp protocol?")
set(CURL_DISABLE_TELNET ON CACHE INTERNAL "Disable curl telnet protocol?")
set(CURL_DISABLE_TFTP ON CACHE INTERNAL "Disable curl tftp protocol?")
-set(CURL_DISABLE_VERBOSE_STRING OFF CACHE INTERNAL "Do not disable curl verbosity")
+set(CURL_DISABLE_VERBOSE_STRINGS OFF CACHE INTERNAL "Do not disable curl verbosity")
set(CURL_HIDDEN_SYMBOLS OFF CACHE INTERNAL "No curl hidden symbols")
-set(CURL_LDAP_WIN OFF CACHE INTERNAL "No curl Windows LDAP")
set(CURL_STATICLIB ON CACHE INTERNAL "Static curl")
-set(CURL_USE_ARES OFF CACHE INTERNAL "No curl c-ares support")
set(DISABLED_THREADSAFE OFF CACHE INTERNAL "Curl can use thread-safe functions")
-set(ENABLE_IPV6 OFF CACHE INTERNAL "Curl IPv6 support")
+set(ENABLE_ARES OFF CACHE INTERNAL "No curl c-ares support")
+set(ENABLE_CURLDEBUG OFF CACHE INTERNAL "No curl TrackMemory features")
+set(ENABLE_DEBUG OFF CACHE INTERNAL "No curl debug features")
+set(ENABLE_IPV6 OFF CACHE INTERNAL "No curl IPv6 support")
+set(ENABLE_MANUAL OFF CACHE INTERNAL "No curl built-in manual")
+set(ENABLE_THREADED_RESOLVER OFF CACHE INTERNAL "No curl POSIX threaded DNS lookup")
+set(ENABLE_UNIX_SOCKETS OFF CACHE INTERNAL "No curl Unix domain sockets support")
set(HTTP_ONLY OFF CACHE INTERNAL "Curl is not http-only")
+set(USE_WIN32_LDAP OFF CACHE INTERNAL "No curl Windows LDAP")
# Windows Vista and above have inet_pton, but this will link on
# older versions and then the executable will fail to launch at
@@ -51,7 +58,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 +103,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 +131,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 +241,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 +313,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 +353,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 +434,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 +495,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 +530,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 +542,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 +557,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 +570,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 +591,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 +696,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 +768,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 +816,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 +836,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 +875,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 +1062,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 +1099,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/README-CMake.txt b/Utilities/cmcurl/README-CMake.txt
index 3f053d8..1e75672 100644
--- a/Utilities/cmcurl/README-CMake.txt
+++ b/Utilities/cmcurl/README-CMake.txt
@@ -11,7 +11,7 @@ branch, but it is merged into our history.
Update curl from upstream as follows. Create a local branch to
explicitly reference the upstream snapshot branch head:
- git branch curl-upstream 3fe5d9bf
+ git branch curl-upstream 70654261
Use a temporary directory to checkout the branch:
@@ -24,7 +24,7 @@ Use a temporary directory to checkout the branch:
Now place the (reduced) curl content in this directory. See
instructions shown by
- git log 3fe5d9bf
+ git log 70654261
for help extracting the content from the upstream repo. Then run
the following commands to commit the new version. Substitute the
@@ -34,8 +34,8 @@ appropriate date and version number:
GIT_AUTHOR_NAME='Curl Upstream' \
GIT_AUTHOR_EMAIL='curl-library@cool.haxx.se' \
- GIT_AUTHOR_DATE='Wed Sep 10 08:07:58 2014 +0200' \
- git commit -m 'curl 7.38.0 (reduced)' &&
+ GIT_AUTHOR_DATE='Tue Aug 11 20:13:01 2015 +0200' \
+ git commit -m 'curl 7.44.0 (reduced)' &&
git commit --amend
Edit the commit message to describe the procedure used to obtain the
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 */
diff --git a/bootstrap b/bootstrap
index d778bbe..7b9a582 100755
--- a/bootstrap
+++ b/bootstrap
@@ -322,11 +322,6 @@ CMAKE_CXX_SOURCES="\
cmExprLexer \
cmExprParser \
cmExprParserHelper \
- cmGlobalNinjaGenerator \
- cmLocalNinjaGenerator \
- cmNinjaTargetGenerator \
- cmNinjaNormalTargetGenerator \
- cmNinjaUtilityTargetGenerator \
"
if ${cmake_system_mingw}; then