Browse Source

curl 7.44.0 (reduced)

Extract upstream curl using the following shell code.

url=git://github.com/bagder/curl.git &&
v=7.44.0 &&
r=1a7f66a3 &&
paths="
  CMake/*
  CMakeLists.txt
  COPYING
  include/curl/*.h
  include/curl/curlbuild.h.cmake
  lib/*.c
  lib/*.h
  lib/CMakeLists.txt
  lib/Makefile.inc
  lib/curl_config.h.cmake
  lib/libcurl.rc
  lib/vtls/*.c
  lib/vtls/*.h
" &&
mkdir curl-$v-g$r-reduced &&
git clone $url curl-git &&
date=$(cd curl-git && git log -n 1 --format='%cd' $r) &&
(cd curl-git && git checkout $r &&
 git archive --format=tar $r -- $paths) |
(cd curl-$v-g$r-reduced && tar xv &&
 rm lib/config-*.h) &&
echo "g$r date: $date"
Curl Upstream 10 years ago
parent
commit
7065426158
100 changed files with 6720 additions and 4719 deletions
  1. 0 71
      CMake/CurlCheckCSourceCompiles.cmake
  2. 0 83
      CMake/CurlCheckCSourceRuns.cmake
  3. 70 246
      CMake/CurlTests.c
  4. 289 0
      CMake/FindGSS.cmake
  5. 12 6
      CMake/Macros.cmake
  6. 90 114
      CMake/OtherTests.cmake
  7. 1 1
      CMake/Platforms/WindowsCache.cmake
  8. 334 96
      CMakeLists.txt
  9. 1 1
      COPYING
  10. 69 25
      include/curl/curl.h
  11. 13 5
      include/curl/curlver.h
  12. 1 8
      include/curl/mprintf.h
  13. 37 1
      include/curl/multi.h
  14. 2 0
      include/curl/typecheck-gcc.h
  15. 5 23
      lib/CMakeLists.txt
  16. 44 42
      lib/Makefile.inc
  17. 2 2
      lib/amigaos.c
  18. 17 20
      lib/asyn-ares.c
  19. 21 24
      lib/asyn-thread.c
  20. 9 14
      lib/base64.c
  21. 0 110
      lib/bundles.c
  22. 130 49
      lib/conncache.c
  23. 17 4
      lib/conncache.h
  24. 135 92
      lib/connect.c
  25. 1 1
      lib/connect.h
  26. 103 105
      lib/cookie.c
  27. 45 14
      lib/curl_addrinfo.c
  28. 4 0
      lib/curl_addrinfo.h
  29. 9 3
      lib/curl_config.h.cmake
  30. 63 0
      lib/curl_des.c
  31. 9 20
      lib/curl_des.h
  32. 236 0
      lib/curl_endian.c
  33. 70 0
      lib/curl_endian.h
  34. 2 5
      lib/curl_fnmatch.c
  35. 49 4
      lib/curl_gssapi.c
  36. 17 2
      lib/curl_gssapi.h
  37. 7 5
      lib/curl_md4.h
  38. 3 0
      lib/curl_memory.h
  39. 2 6
      lib/curl_memrchr.c
  40. 9 9
      lib/curl_multibyte.c
  41. 7 5
      lib/curl_multibyte.h
  42. 35 44
      lib/curl_ntlm.c
  43. 3 7
      lib/curl_ntlm.h
  44. 203 89
      lib/curl_ntlm_core.c
  45. 38 21
      lib/curl_ntlm_core.h
  46. 134 327
      lib/curl_ntlm_msgs.c
  47. 0 34
      lib/curl_ntlm_msgs.h
  48. 21 25
      lib/curl_ntlm_wb.c
  49. 4 3
      lib/curl_ntlm_wb.h
  50. 56 0
      lib/curl_printf.h
  51. 11 16
      lib/curl_rtmp.c
  52. 1043 115
      lib/curl_sasl.c
  53. 130 34
      lib/curl_sasl.h
  54. 392 0
      lib/curl_sasl_gssapi.c
  55. 671 102
      lib/curl_sasl_sspi.c
  56. 2 2
      lib/curl_sec.h
  57. 45 8
      lib/curl_setup.h
  58. 15 15
      lib/curl_sspi.c
  59. 111 80
      lib/curl_sspi.h
  60. 8 7
      lib/curl_threads.c
  61. 7 2
      lib/curl_threads.h
  62. 2 3
      lib/curlx.h
  63. 6 10
      lib/dict.c
  64. 64 116
      lib/easy.c
  65. 13 15
      lib/escape.c
  66. 33 30
      lib/file.c
  67. 1 5
      lib/fileinfo.c
  68. 41 86
      lib/formdata.c
  69. 159 146
      lib/ftp.c
  70. 5 6
      lib/ftp.h
  71. 26 31
      lib/ftplistparser.c
  72. 28 27
      lib/getinfo.c
  73. 6 10
      lib/gopher.c
  74. 20 52
      lib/hash.c
  75. 2 8
      lib/hash.h
  76. 1 5
      lib/hmac.c
  77. 10 14
      lib/hostasyn.c
  78. 3 4
      lib/hostcheck.c
  79. 155 132
      lib/hostip.c
  80. 11 11
      lib/hostip.h
  81. 6 9
      lib/hostip4.c
  82. 7 10
      lib/hostip6.c
  83. 1 5
      lib/hostsyn.c
  84. 226 152
      lib/http.c
  85. 46 18
      lib/http.h
  86. 532 214
      lib/http2.c
  87. 14 3
      lib/http2.h
  88. 4 8
      lib/http_chunks.c
  89. 65 484
      lib/http_digest.c
  90. 3 18
      lib/http_digest.h
  91. 65 98
      lib/http_negotiate.c
  92. 3 3
      lib/http_negotiate.h
  93. 64 54
      lib/http_negotiate_sspi.c
  94. 31 33
      lib/http_proxy.c
  95. 4 3
      lib/http_proxy.h
  96. 26 3
      lib/idn_win32.c
  97. 70 17
      lib/if2ip.c
  98. 11 2
      lib/if2ip.h
  99. 88 708
      lib/imap.c
  100. 4 19
      lib/imap.h

+ 0 - 71
CMake/CurlCheckCSourceCompiles.cmake

@@ -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("${VAR}" MATCHES "^${VAR}$" OR "${VAR}" MATCHES "UNKNOWN")
-    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()

+ 0 - 83
CMake/CurlCheckCSourceRuns.cmake

@@ -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("${VAR}" MATCHES "^${VAR}$" OR "${VAR}" MATCHES "UNKNOWN")
-    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("${VAR}" MATCHES "^${VAR}$" OR "${VAR}" MATCHES "UNKNOWN")
-endmacro(CURL_CHECK_C_SOURCE_RUNS)

+ 70 - 246
CMake/CurlTests.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2011, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2014, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -71,264 +71,88 @@ main ()
 }
 #endif
 
-#ifdef HAVE_GETHOSTBYADDR_R_5
+/* tests for gethostbyaddr_r or gethostbyname_r */
+#if defined(HAVE_GETHOSTBYADDR_R_5_REENTRANT) || \
+    defined(HAVE_GETHOSTBYADDR_R_7_REENTRANT) || \
+    defined(HAVE_GETHOSTBYADDR_R_8_REENTRANT) || \
+    defined(HAVE_GETHOSTBYNAME_R_3_REENTRANT) || \
+    defined(HAVE_GETHOSTBYNAME_R_5_REENTRANT) || \
+    defined(HAVE_GETHOSTBYNAME_R_6_REENTRANT)
+#   define _REENTRANT
+    /* no idea whether _REENTRANT is always set, just invent a new flag */
+#   define TEST_GETHOSTBYFOO_REENTRANT
+#endif
+#if defined(HAVE_GETHOSTBYADDR_R_5) || \
+    defined(HAVE_GETHOSTBYADDR_R_7) || \
+    defined(HAVE_GETHOSTBYADDR_R_8) || \
+    defined(HAVE_GETHOSTBYNAME_R_3) || \
+    defined(HAVE_GETHOSTBYNAME_R_5) || \
+    defined(HAVE_GETHOSTBYNAME_R_6) || \
+    defined(TEST_GETHOSTBYFOO_REENTRANT)
 #include <sys/types.h>
 #include <netdb.h>
-int
-main ()
-{
-
-char * address;
-int length;
-int type;
-struct hostent h;
-struct hostent_data hdata;
-int rc;
-#ifndef gethostbyaddr_r
-  (void)gethostbyaddr_r;
-#endif
-rc = gethostbyaddr_r(address, length, type, &h, &hdata);
-  ;
-  return 0;
-}
-#endif
-#ifdef HAVE_GETHOSTBYADDR_R_5_REENTRANT
-#define _REENTRANT
-#include <sys/types.h>
-#include <netdb.h>
-int
-main ()
-{
-
-char * address;
-int length;q
-int type;
-struct hostent h;
-struct hostent_data hdata;
-int rc;
-#ifndef gethostbyaddr_r
-  (void)gethostbyaddr_r;
-#endif
-rc = gethostbyaddr_r(address, length, type, &h, &hdata);
-  ;
-  return 0;
-}
-#endif
-#ifdef HAVE_GETHOSTBYADDR_R_7
-#include <sys/types.h>
-#include <netdb.h>
-int
-main ()
-{
-
-char * address;
-int length;
-int type;
-struct hostent h;
-char buffer[8192];
-int h_errnop;
-struct hostent * hp;
-
-#ifndef gethostbyaddr_r
-  (void)gethostbyaddr_r;
-#endif
-hp = gethostbyaddr_r(address, length, type, &h,
-                     buffer, 8192, &h_errnop);
-  ;
-  return 0;
-}
-#endif
-#ifdef HAVE_GETHOSTBYADDR_R_7_REENTRANT
-#define _REENTRANT
-#include <sys/types.h>
-#include <netdb.h>
-int
-main ()
+int main(void)
 {
-
-char * address;
-int length;
-int type;
-struct hostent h;
-char buffer[8192];
-int h_errnop;
-struct hostent * hp;
-
-#ifndef gethostbyaddr_r
-  (void)gethostbyaddr_r;
-#endif
-hp = gethostbyaddr_r(address, length, type, &h,
-                     buffer, 8192, &h_errnop);
-  ;
-  return 0;
-}
+  char *address = "example.com";
+  int length = 0;
+  int type = 0;
+  struct hostent h;
+  int rc = 0;
+#if defined(HAVE_GETHOSTBYADDR_R_5) || \
+    defined(HAVE_GETHOSTBYADDR_R_5_REENTRANT) || \
+    \
+    defined(HAVE_GETHOSTBYNAME_R_3) || \
+    defined(HAVE_GETHOSTBYNAME_R_3_REENTRANT)
+  struct hostent_data hdata;
+#elif defined(HAVE_GETHOSTBYADDR_R_7) || \
+      defined(HAVE_GETHOSTBYADDR_R_7_REENTRANT) || \
+      defined(HAVE_GETHOSTBYADDR_R_8) || \
+      defined(HAVE_GETHOSTBYADDR_R_8_REENTRANT) || \
+      \
+      defined(HAVE_GETHOSTBYNAME_R_5) || \
+      defined(HAVE_GETHOSTBYNAME_R_5_REENTRANT) || \
+      defined(HAVE_GETHOSTBYNAME_R_6) || \
+      defined(HAVE_GETHOSTBYNAME_R_6_REENTRANT)
+  char buffer[8192];
+  int h_errnop;
+  struct hostent *hp;
 #endif
-#ifdef HAVE_GETHOSTBYADDR_R_8
-#include <sys/types.h>
-#include <netdb.h>
-int
-main ()
-{
-
-char * address;
-int length;
-int type;
-struct hostent h;
-char buffer[8192];
-int h_errnop;
-struct hostent * hp;
-int rc;
-
-#ifndef gethostbyaddr_r
-  (void)gethostbyaddr_r;
-#endif
-rc = gethostbyaddr_r(address, length, type, &h,
-                     buffer, 8192, &hp, &h_errnop);
-  ;
-  return 0;
-}
-#endif
-#ifdef HAVE_GETHOSTBYADDR_R_8_REENTRANT
-#define _REENTRANT
-#include <sys/types.h>
-#include <netdb.h>
-int
-main ()
-{
-
-char * address;
-int length;
-int type;
-struct hostent h;
-char buffer[8192];
-int h_errnop;
-struct hostent * hp;
-int rc;
 
 #ifndef gethostbyaddr_r
   (void)gethostbyaddr_r;
 #endif
-rc = gethostbyaddr_r(address, length, type, &h,
-                     buffer, 8192, &hp, &h_errnop);
-  ;
-  return 0;
-}
-#endif
-#ifdef HAVE_GETHOSTBYNAME_R_3
-#include <string.h>
-#include <sys/types.h>
-#include <netdb.h>
-#undef NULL
-#define NULL (void *)0
-
-int
-main ()
-{
-
-struct hostent_data data;
-#ifndef gethostbyname_r
-  (void)gethostbyname_r;
-#endif
-gethostbyname_r(NULL, NULL, NULL);
-  ;
-  return 0;
-}
-#endif
-#ifdef HAVE_GETHOSTBYNAME_R_3_REENTRANT
-#define _REENTRANT
-#include <string.h>
-#include <sys/types.h>
-#include <netdb.h>
-#undef NULL
-#define NULL (void *)0
-
-int
-main ()
-{
-
-struct hostent_data data;
-#ifndef gethostbyname_r
-  (void)gethostbyname_r;
-#endif
-gethostbyname_r(NULL, NULL, NULL);
-  ;
-  return 0;
-}
-#endif
-#ifdef HAVE_GETHOSTBYNAME_R_5
-#include <sys/types.h>
-#include <netinet/in.h>
-#include <netdb.h>
-#undef NULL
-#define NULL (void *)0
-
-int
-main ()
-{
-#ifndef gethostbyname_r
-  (void)gethostbyname_r;
-#endif
-gethostbyname_r(NULL, NULL, NULL, 0, NULL);
-  ;
-  return 0;
-}
-#endif
-#ifdef HAVE_GETHOSTBYNAME_R_5_REENTRANT
-#define _REENTRANT
-#include <sys/types.h>
-#include <netdb.h>
-#undef NULL
-#define NULL (void *)0
 
-int
-main ()
-{
-
-#ifndef gethostbyname_r
-  (void)gethostbyname_r;
-#endif
-gethostbyname_r(NULL, NULL, NULL, 0, NULL);
-  ;
+#if   defined(HAVE_GETHOSTBYADDR_R_5) || \
+      defined(HAVE_GETHOSTBYADDR_R_5_REENTRANT)
+  rc = gethostbyaddr_r(address, length, type, &h, &hdata);
+#elif defined(HAVE_GETHOSTBYADDR_R_7) || \
+      defined(HAVE_GETHOSTBYADDR_R_7_REENTRANT)
+  hp = gethostbyaddr_r(address, length, type, &h, buffer, 8192, &h_errnop);
+  (void)hp;
+#elif defined(HAVE_GETHOSTBYADDR_R_8) || \
+      defined(HAVE_GETHOSTBYADDR_R_8_REENTRANT)
+  rc = gethostbyaddr_r(address, length, type, &h, buffer, 8192, &hp, &h_errnop);
+#endif
+
+#if   defined(HAVE_GETHOSTBYNAME_R_3) || \
+      defined(HAVE_GETHOSTBYNAME_R_3_REENTRANT)
+  rc = gethostbyname_r(address, &h, &hdata);
+#elif defined(HAVE_GETHOSTBYNAME_R_5) || \
+      defined(HAVE_GETHOSTBYNAME_R_5_REENTRANT)
+  rc = gethostbyname_r(address, &h, buffer, 8192, 0, &h_errnop);
+  (void)hp; /* not used for test */
+#elif defined(HAVE_GETHOSTBYNAME_R_6) || \
+      defined(HAVE_GETHOSTBYNAME_R_6_REENTRANT)
+  rc = gethostbyname_r(address, &h, buffer, 8192, &hp, &h_errnop);
+#endif
+
+  (void)length;
+  (void)type;
+  (void)rc;
   return 0;
 }
 #endif
-#ifdef HAVE_GETHOSTBYNAME_R_6
-#include <sys/types.h>
-#include <netdb.h>
-#undef NULL
-#define NULL (void *)0
-
-int
-main ()
-{
 
-#ifndef gethostbyname_r
-  (void)gethostbyname_r;
-#endif
-gethostbyname_r(NULL, NULL, NULL, 0, NULL, NULL);
-  ;
-  return 0;
-}
-#endif
-#ifdef HAVE_GETHOSTBYNAME_R_6_REENTRANT
-#define _REENTRANT
-#include <sys/types.h>
-#include <netdb.h>
-#undef NULL
-#define NULL (void *)0
-
-int
-main ()
-{
-
-#ifndef gethostbyname_r
-  (void)gethostbyname_r;
-#endif
-gethostbyname_r(NULL, NULL, NULL, 0, NULL, NULL);
-  ;
-  return 0;
-}
-#endif
 #ifdef HAVE_SOCKLEN_T
 #ifdef _WIN32
 #include <ws2tcpip.h>

+ 289 - 0
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)

+ 12 - 6
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,8 +14,11 @@ 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_file("${FILE}" ${VARIABLE})
+  check_include_files("${CURL_INCLUDES};${FILE}" ${VARIABLE})
   if(${VARIABLE})
     set(CURL_INCLUDES ${CURL_INCLUDES} ${FILE})
     set(CURL_TEST_DEFINES "${CURL_TEST_DEFINES} -D${VARIABLE}")
@@ -21,7 +27,7 @@ endmacro(CHECK_INCLUDE_FILE_CONCAT)
 
 # For other curl specific tests, use this macro.
 macro(CURL_INTERNAL_TEST CURL_TEST)
-  if("${CURL_TEST}" MATCHES "^${CURL_TEST}$")
+  if(NOT DEFINED "${CURL_TEST}")
     set(MACRO_CHECK_FUNCTION_DEFINITIONS
       "-D${CURL_TEST} ${CURL_TEST_DEFINES} ${CMAKE_REQUIRED_FLAGS}")
     if(CMAKE_REQUIRED_LIBRARIES)
@@ -49,11 +55,11 @@ macro(CURL_INTERNAL_TEST CURL_TEST)
         "Performing Curl Test ${CURL_TEST} failed with the following output:\n"
         "${OUTPUT}\n")
     endif(${CURL_TEST})
-  endif("${CURL_TEST}" MATCHES "^${CURL_TEST}$")
+  endif()
 endmacro(CURL_INTERNAL_TEST)
 
 macro(CURL_INTERNAL_TEST_RUN CURL_TEST)
-  if("${CURL_TEST}_COMPILE" MATCHES "^${CURL_TEST}_COMPILE$")
+  if(NOT DEFINED "${CURL_TEST}_COMPILE")
     set(MACRO_CHECK_FUNCTION_DEFINITIONS
       "-D${CURL_TEST} ${CMAKE_REQUIRED_FLAGS}")
     if(CMAKE_REQUIRED_LIBRARIES)
@@ -85,5 +91,5 @@ macro(CURL_INTERNAL_TEST_RUN CURL_TEST)
       file(APPEND "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log"
         "\n\n")
     endif(${CURL_TEST}_COMPILE AND NOT ${CURL_TEST})
-  endif("${CURL_TEST}_COMPILE" MATCHES "^${CURL_TEST}_COMPILE$")
+  endif()
 endmacro(CURL_INTERNAL_TEST_RUN)

+ 90 - 114
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")
@@ -44,17 +37,23 @@ if(curl_cv_recv)
           foreach(recv_arg3 "size_t" "int" "socklen_t" "unsigned int")
             foreach(recv_arg4 "int" "unsigned int")
               if(NOT curl_cv_func_recv_done)
-                set(curl_cv_func_recv_test "UNKNOWN")
-                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("
+                unset(curl_cv_func_recv_test CACHE)
+                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")
@@ -107,19 +101,24 @@ if(curl_cv_send)
           foreach(send_arg3 "size_t" "int" "socklen_t" "unsigned int")
             foreach(send_arg4 "int" "unsigned int")
               if(NOT curl_cv_func_send_done)
-                set(curl_cv_func_send_test "UNKNOWN")
-                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("
+                unset(curl_cv_func_send_test CACHE)
+                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)

+ 1 - 1
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)

+ 334 - 96
CMakeLists.txt

@@ -5,7 +5,7 @@
 #                            | (__| |_| |  _ <| |___
 #                             \___|\___/|_| \_\_____|
 #
-# Copyright (C) 1998 - 2014, Daniel Stenberg, <[email protected]>, et al.
+# Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, 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,27 +48,17 @@ project( CURL C )
 message(WARNING "the curl cmake build system is poorly maintained. Be aware")
 
 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})
 message(STATUS "curl version=[${CURL_VERSION}]")
 # SET(PACKAGE_TARNAME "curl")
 # SET(PACKAGE_NAME "curl")
@@ -84,12 +74,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})
@@ -171,9 +184,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}")
@@ -200,9 +256,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
 check_library_exists_concat("dl"     dlopen       HAVE_LIBDL)
 check_library_exists_concat("socket" connect      HAVE_LIBSOCKET)
@@ -219,19 +288,49 @@ 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()
 
+option(CMAKE_USE_OPENSSL "Use OpenSSL code. Experimental" ON)
+mark_as_advanced(CMAKE_USE_OPENSSL)
+
+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)
+  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()
@@ -241,13 +340,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()
@@ -301,8 +401,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()
@@ -336,9 +436,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})
-
 option(CURL_ZLIB "Set to ON to enable building cURL with zlib support." ON)
 set(HAVE_LIBZ OFF)
 set(HAVE_ZLIB_H OFF)
@@ -350,39 +447,10 @@ if(CURL_ZLIB)
     set(HAVE_ZLIB ON)
     set(HAVE_LIBZ ON)
     list(APPEND CURL_LIBS ${ZLIB_LIBRARIES})
+    include_directories(${ZLIB_INCLUDE_DIRS})
   endif()
 endif()
 
-option(CMAKE_USE_OPENSSL "Use OpenSSL code. Experimental" ON)
-mark_as_advanced(CMAKE_USE_OPENSSL)
-
-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_concat("openssl/crypto.h" HAVE_OPENSSL_CRYPTO_H)
-    check_include_file_concat("openssl/engine.h" HAVE_OPENSSL_ENGINE_H)
-    check_include_file_concat("openssl/err.h"    HAVE_OPENSSL_ERR_H)
-    check_include_file_concat("openssl/pem.h"    HAVE_OPENSSL_PEM_H)
-    check_include_file_concat("openssl/pkcs12.h" HAVE_OPENSSL_PKCS12_H)
-    check_include_file_concat("openssl/rsa.h"    HAVE_OPENSSL_RSA_H)
-    check_include_file_concat("openssl/ssl.h"    HAVE_OPENSSL_SSL_H)
-    check_include_file_concat("openssl/x509.h"   HAVE_OPENSSL_X509_H)
-    check_include_file_concat("openssl/rand.h"   HAVE_OPENSSL_RAND_H)
-  endif(OPENSSL_FOUND)
-endif(CMAKE_USE_OPENSSL)
-
 #libSSH2
 option(CMAKE_USE_LIBSSH2 "Use libSSH2" ON)
 mark_as_advanced(CMAKE_USE_LIBSSH2)
@@ -396,6 +464,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)
 
@@ -416,20 +485,82 @@ 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)
+
+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()
+  unset(USE_UNIX_SOCKETS CACHE)
+endif()
 
 # 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)
-endif(NOT UNIX)
-check_include_file_concat("stdio.h"          HAVE_STDIO_H)
 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)
 endif(NOT UNIX)
 
+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)
@@ -454,9 +585,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)
@@ -576,6 +704,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)
@@ -618,7 +752,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)
@@ -639,6 +772,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)
@@ -677,12 +811,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
@@ -869,24 +998,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)
@@ -911,6 +1022,133 @@ if(BUILD_CURL_TESTS)
   add_subdirectory(tests)
 endif()
 
+# 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")

+ 1 - 1
COPYING

@@ -1,6 +1,6 @@
 COPYRIGHT AND PERMISSION NOTICE
 
-Copyright (c) 1996 - 2014, Daniel Stenberg, <[email protected]>.
+Copyright (c) 1996 - 2015, Daniel Stenberg, <[email protected]>.
 
 All rights reserved.
 

+ 69 - 25
include/curl/curl.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2014, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, 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()

+ 13 - 5
include/curl/curlver.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2014, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, 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, <[email protected]>."
+#define LIBCURL_COPYRIGHT "1996 - 2015 Daniel Stenberg, <[email protected]>."
 
 /* This is the version number of the libcurl package from which this header
    file origins: */
-#define LIBCURL_VERSION "7.38.0-DEV"
+#define LIBCURL_VERSION "7.44.0-DEV"
 
 /* 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 */

+ 1 - 8
include/curl/mprintf.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2013, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, 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

+ 37 - 1
include/curl/multi.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2013, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, 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

+ 2 - 0
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 */

+ 5 - 23
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()
 
@@ -106,8 +87,6 @@ endif()
 
 set_target_properties(${LIB_NAME} PROPERTIES COMPILE_DEFINITIONS BUILDING_LIBCURL)
 
-setup_curl_dependencies(${LIB_NAME})
-
 # Remove the "lib" prefix since the library is already named "libcurl".
 set_target_properties(${LIB_NAME} PROPERTIES PREFIX "")
 set_target_properties(${LIB_NAME} PROPERTIES IMPORT_PREFIX "")
@@ -119,4 +98,7 @@ if(WIN32)
   endif()
 endif()
 
-install(TARGETS ${LIB_NAME} DESTINATION lib)
+install(TARGETS ${LIB_NAME}
+  ARCHIVE DESTINATION lib
+  LIBRARY DESTINATION lib
+  RUNTIME DESTINATION bin)

+ 44 - 42
lib/Makefile.inc

@@ -5,7 +5,7 @@
 #                            | (__| |_| |  _ <| |___
 #                             \___|\___/|_| \_\_____|
 #
-# Copyright (C) 1998 - 2014, Daniel Stenberg, <[email protected]>, et al.
+# Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, 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
 

+ 2 - 2
lib/amigaos.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2012, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, 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__ */

+ 17 - 20
lib/asyn-ares.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2014, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, 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;
     }

+ 21 - 24
lib/asyn-thread.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2014, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, 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 */

+ 9 - 14
lib/base64.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2014, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, 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 */
 

+ 0 - 110
lib/bundles.c

@@ -1,110 +0,0 @@
-/***************************************************************************
- *                                  _   _ ____  _
- *  Project                     ___| | | |  _ \| |
- *                             / __| | | | |_) | |
- *                            | (__| |_| |  _ <| |___
- *                             \___|\___/|_| \_\_____|
- *
- * Copyright (C) 2012, Linus Nielsen Feltzing, <[email protected]>
- * Copyright (C) 2012, Daniel Stenberg, <[email protected]>, 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;
-}

+ 130 - 49
lib/conncache.c

@@ -6,7 +6,7 @@
  *                             \___|\___/|_| \_\_____|
  *
  * Copyright (C) 2012, Linus Nielsen Feltzing, <[email protected]>
- * Copyright (C) 2012 - 2014, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 2012 - 2015, Daniel Stenberg, <[email protected]>, 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;

+ 17 - 4
lib/conncache.h

@@ -7,6 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
+ * Copyright (C) 2015, Daniel Stenberg, <[email protected]>, et al.
  * Copyright (C) 2012 - 2014, Linus Nielsen Feltzing, <[email protected]>
  *
  * 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);

+ 135 - 92
lib/connect.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2014, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, 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

+ 1 - 1
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

+ 103 - 105
lib/cookie.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2014, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, 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;

+ 45 - 14
lib/curl_addrinfo.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2012, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2014, Daniel Stenberg, <[email protected]>, 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()

+ 4 - 0
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,

+ 9 - 3
lib/curl_config.h.cmake

@@ -53,7 +53,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
@@ -467,6 +467,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
 
@@ -879,6 +882,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
 
@@ -903,8 +909,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
 
 /* Define to 1 if you are building a Windows target without large file
    support. */

+ 63 - 0
lib/curl_des.c

@@ -0,0 +1,63 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2015, Steve Holme, <[email protected]>.
+ *
+ * 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) */

+ 9 - 20
lib/bundles.h → 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, <[email protected]>
+ * Copyright (C) 2015, Steve Holme, <[email protected]>.
  *
  * 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 */

+ 236 - 0
lib/curl_endian.c

@@ -0,0 +1,236 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, 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 */

+ 70 - 0
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, <[email protected]>, 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 */

+ 2 - 5
lib/curl_fnmatch.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2011, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, 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"
 

+ 49 - 4
lib/curl_gssapi.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2011 - 2014, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 2011 - 2015, Daniel Stenberg, <[email protected]>, 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 */

+ 17 - 2
lib/curl_gssapi.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2011, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 2011 - 2015, Daniel Stenberg, <[email protected]>, 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 */

+ 7 - 5
lib/curl_md4.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2010, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2014, Daniel Stenberg, <[email protected]>, 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 */

+ 3 - 0
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

+ 2 - 6
lib/curl_memrchr.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2011, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, 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"
 

+ 9 - 9
lib/curl_multibyte.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2012, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, 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) */

+ 7 - 5
lib/curl_multibyte.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2012, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, 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 */

+ 35 - 44
lib/curl_ntlm.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2014, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, 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 */

+ 3 - 7
lib/curl_ntlm.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2011, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2014, Daniel Stenberg, <[email protected]>, 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 */

+ 203 - 89
lib/curl_ntlm_core.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2014, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, 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 */

+ 38 - 21
lib/curl_ntlm_core.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2014, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, 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 */

+ 134 - 327
lib/curl_ntlm_msgs.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2014, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, 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 */

+ 0 - 34
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
 

+ 21 - 25
lib/curl_ntlm_wb.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2014, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, 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 */

+ 4 - 3
lib/curl_ntlm_wb.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2011, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2014, Daniel Stenberg, <[email protected]>, 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 */

+ 56 - 0
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, <[email protected]>, 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 */

+ 11 - 16
lib/curl_rtmp.c

@@ -5,7 +5,7 @@
  *                | (__| |_| |  _ <| |___
  *                 \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2012 - 2014, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 2012 - 2015, Daniel Stenberg, <[email protected]>, et al.
  * Copyright (C) 2010, Howard Chu, <[email protected]>
  *
  * 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));
 

+ 1043 - 115
lib/curl_sasl.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2012 - 2014, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 2012 - 2015, Daniel Stenberg, <[email protected]>, 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;
+}

+ 130 - 34
lib/curl_sasl.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2012 - 2014, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 2012 - 2015, Daniel Stenberg, <[email protected]>, 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 */

+ 392 - 0
lib/curl_sasl_gssapi.c

@@ -0,0 +1,392 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2014 - 2015, Steve Holme, <[email protected]>.
+ * Copyright (C) 2015, Daniel Stenberg, <[email protected]>, 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 */

File diff suppressed because it is too large
+ 671 - 102
lib/curl_sasl_sspi.c


+ 2 - 2
lib/curl_sec.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2013, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2014, Daniel Stenberg, <[email protected]>, 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 *);
 };
 

+ 45 - 8
lib/curl_setup.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2013, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -190,6 +190,9 @@
 #  ifndef CURL_DISABLE_GOPHER
 #    define CURL_DISABLE_GOPHER
 #  endif
+#  ifndef CURL_DISABLE_SMB
+#    define CURL_DISABLE_SMB
+#  endif
 #endif
 
 /*
@@ -601,26 +604,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)
@@ -636,8 +651,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
 
 /*
@@ -690,4 +707,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 */

+ 15 - 15
lib/curl_sspi.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2012, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, 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;

+ 111 - 80
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

+ 8 - 7
lib/curl_threads.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2013, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, 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);
 

+ 7 - 2
lib/curl_threads.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2010, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2014, Daniel Stenberg, <[email protected]>, 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)

+ 2 - 3
lib/curlx.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2008, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, 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

+ 6 - 10
lib/dict.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2014, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, 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;
   }

+ 64 - 116
lib/easy.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2014, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, 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;
 }

+ 13 - 15
lib/escape.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2014, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, 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);
 }

+ 33 - 30
lib/file.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2014, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, 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

+ 1 - 5
lib/fileinfo.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2010-2011, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 2010 - 2015, Daniel Stenberg, <[email protected]>, 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"

+ 41 - 86
lib/formdata.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2014, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, 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))
@@ -212,46 +207,6 @@ static const char *ContentTypeForFilename(const char *filename,
   return contenttype;
 }
 
-/***************************************************************************
- *
- * 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()
@@ -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");

+ 159 - 146
lib/ftp.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2014, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, 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);
@@ -3801,7 +3819,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)
@@ -3809,7 +3827,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, '/');
@@ -3817,8 +3835,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);
@@ -3836,8 +3854,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;
     }
   }
 
@@ -3855,7 +3873,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;
   }
 
@@ -3867,13 +3885,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);
@@ -3902,16 +3920,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: {
@@ -3975,10 +3993,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);
@@ -4002,11 +4019,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:
@@ -4014,7 +4031,7 @@ static CURLcode wc_statemach(struct connectdata *conn)
     break;
   }
 
-  return ret;
+  return result;
 }
 
 /***********************************************************************
@@ -4028,31 +4045,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;
 }
 
 
@@ -4064,7 +4081,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
@@ -4079,23 +4096,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)
@@ -4110,7 +4127,7 @@ CURLcode Curl_ftpsendf(struct connectdata *conn,
       break;
   }
 
-  return res;
+  return result;
 }
 
 /***********************************************************************
@@ -4181,14 +4198,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);
 
@@ -4479,7 +4492,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 */

+ 5 - 6
lib/ftp.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2013, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, 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 */
 
 };
 

+ 26 - 31
lib/ftplistparser.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2014, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, 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++;

+ 28 - 27
lib/getinfo.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2014, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, 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;
 }

+ 6 - 10
lib/gopher.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2012, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, 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;
   }

+ 20 - 52
lib/hash.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2013, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, 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;
 }

+ 2 - 8
lib/hash.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2007, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, 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);

+ 1 - 5
lib/hmac.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2011, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, 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"

+ 10 - 14
lib/hostasyn.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2012, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, 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;
 }
 
 /*

+ 3 - 4
lib/hostcheck.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2014, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, 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 */

+ 155 - 132
lib/hostip.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2014, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, 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);

+ 11 - 11
lib/hostip.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2013, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, 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.
  *

+ 6 - 9
lib/hostip4.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2013, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, 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.

+ 7 - 10
lib/hostip6.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2013, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, 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));

+ 1 - 5
lib/hostsyn.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2013, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, 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"

+ 226 - 152
lib/http.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2014, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, 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 */
 
@@ -1022,6 +1032,16 @@ Curl_send_buffer *Curl_add_buffer_init(void)
   return calloc(1, sizeof(Curl_send_buffer));
 }
 
+/*
+ * Curl_add_buffer_free() frees all associated resources.
+ */
+void Curl_add_buffer_free(Curl_send_buffer *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;

+ 46 - 18
lib/http.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2014, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, 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

File diff suppressed because it is too large
+ 532 - 214
lib/http2.c


+ 14 - 3
lib/http2.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2014, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, 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 */

+ 4 - 8
lib/http_chunks.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2014, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, 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. "

+ 65 - 484
lib/http_digest.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2014, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, 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

+ 3 - 18
lib/http_digest.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2011, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2014, Daniel Stenberg, <[email protected]>, 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,

+ 65 - 98
lib/http_negotiate.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2014, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, 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 */

+ 3 - 3
lib/http_negotiate.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2011, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, 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);

+ 64 - 54
lib/http_negotiate_sspi.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2014, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, 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)

+ 31 - 33
lib/http_proxy.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2014, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, 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]);

+ 4 - 3
lib/http_proxy.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2014, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, 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
 

+ 26 - 3
lib/idn_win32.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2012, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2014, Daniel Stenberg, <[email protected]>, 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

+ 70 - 17
lib/if2ip.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2013, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, 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;

+ 11 - 2
lib/if2ip.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2012, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2014, Daniel Stenberg, <[email protected]>, 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
 

File diff suppressed because it is too large
+ 88 - 708
lib/imap.c


+ 4 - 19
lib/imap.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2009 - 2014, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 2009 - 2015, Daniel Stenberg, <[email protected]>, 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 */
 };

Some files were not shown because too many files changed in this diff