]> granicus.if.org Git - curl/commitdiff
NTLM: END of refactoring/splitting/moving
authorYang Tse <yangsita@gmail.com>
Sun, 28 Aug 2011 00:00:02 +0000 (02:00 +0200)
committerYang Tse <yangsita@gmail.com>
Sun, 28 Aug 2011 00:00:02 +0000 (02:00 +0200)
First:

File curl_ntlm.h renamed curl_ntlm_msgs.h
File curl_ntlm.c renamed curl_ntlm_msgs.c

Afterwards:

File http_ntlm.c renamed curl_ntlm.c
File http_ntlm.h renamed curl_ntlm.h

13 files changed:
lib/Makefile.inc
lib/Makefile.vc6
lib/curl_ntlm.c
lib/curl_ntlm.h
lib/curl_ntlm_msgs.c [new file with mode: 0644]
lib/curl_ntlm_msgs.h [new file with mode: 0644]
lib/easy.c
lib/http.c
lib/http_ntlm.c [deleted file]
lib/http_ntlm.h [deleted file]
lib/transfer.c
lib/url.c
packages/Symbian/group/libcurl.mmp

index 3778fbcf02da2301bec85c7730538e1ab323c041..ec7f505377b062b4b34b1ef79f3f34e688568af5 100644 (file)
@@ -14,7 +14,7 @@ CSOURCES = file.c timeval.c base64.c hostip.c progress.c formdata.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 curl_rand.c     \
-  http_negotiate.c http_ntlm.c inet_pton.c strtoofft.c strerror.c      \
+  http_negotiate.c inet_pton.c strtoofft.c strerror.c                  \
   hostasyn.c hostip4.c hostip6.c hostsyn.c inet_ntop.c parsedate.c     \
   select.c gtls.c sslgen.c tftp.c splay.c strdup.c socks.c ssh.c nss.c \
   qssl.c rawstr.c curl_addrinfo.c socks_gssapi.c socks_sspi.c          \
@@ -23,7 +23,7 @@ CSOURCES = file.c timeval.c base64.c hostip.c progress.c formdata.c   \
   curl_rtmp.c openldap.c curl_gethostname.c gopher.c axtls.c           \
   idn_win32.c http_negotiate_sspi.c cyassl.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_core.c curl_ntlm_msgs.c
 
 HHEADERS = arpa_telnet.h netrc.h file.h timeval.h qssl.h hostip.h      \
   progress.h formdata.h cookie.h http.h sendf.h ftp.h url.h dict.h     \
@@ -31,7 +31,7 @@ HHEADERS = arpa_telnet.h netrc.h file.h timeval.h qssl.h hostip.h     \
   getinfo.h strequal.h krb4.h memdebug.h http_chunks.h curl_rand.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 http_ntlm.h inet_pton.h    \
+  curl_md5.h http_digest.h http_negotiate.h inet_pton.h                        \
   strtoofft.h strerror.h inet_ntop.h curlx.h curl_memory.h setup.h     \
   transfer.h select.h easyif.h multiif.h parsedate.h sslgen.h gtls.h   \
   tftp.h sockaddr.h splay.h strdup.h setup_once.h socks.h ssh.h nssg.h \
@@ -39,4 +39,4 @@ HHEADERS = arpa_telnet.h netrc.h file.h timeval.h qssl.h hostip.h     \
   curl_memrchr.h imap.h pop3.h smtp.h pingpong.h rtsp.h curl_threads.h \
   warnless.h curl_hmac.h polarssl.h curl_rtmp.h curl_gethostname.h     \
   gopher.h axtls.h cyassl.h http_proxy.h non-ascii.h asyn.h curl_ntlm.h \
-  curl_gssapi.h curl_ntlm_wb.h curl_ntlm_core.h
+  curl_gssapi.h curl_ntlm_wb.h curl_ntlm_core.h curl_ntlm_msgs.h
index d3b11d993e095affe1d6d6b823ba8d8caafe34b1..fb7566660b3aac90835247a1161990ad1cd78e01 100644 (file)
@@ -508,6 +508,7 @@ X_OBJS= \
        $(DIROBJ)\curl_memrchr.obj \\r
        $(DIROBJ)\curl_ntlm.obj \\r
        $(DIROBJ)\curl_ntlm_core.obj \\r
+       $(DIROBJ)\curl_ntlm_msgs.obj \\r
        $(DIROBJ)\curl_ntlm_wb.obj \\r
        $(DIROBJ)\curl_rand.obj \\r
        $(DIROBJ)\curl_rtmp.obj \\r
@@ -536,7 +537,6 @@ X_OBJS= \
        $(DIROBJ)\http_digest.obj \\r
        $(DIROBJ)\http_negotiate.obj \\r
         $(DIROBJ)\http_negotiate_sspi.obj \\r
-       $(DIROBJ)\http_ntlm.obj \\r
        $(DIROBJ)\http.obj \\r
        $(DIROBJ)\http_proxy.obj \\r
        $(DIROBJ)\if2ip.obj \\r
index 4398d146c157ef12c2b6455cb5475eeb1314cea4..50659b0ccb110b5aeb15f08a95a8bcbcdde602d3 100644 (file)
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+#ifdef HAVE_SIGNAL_H
+#include <signal.h>
+#endif
 
 #if (defined(NETWARE) && !defined(__NOVELL_LIBC__))
 #include <netdb.h>
 #endif
 
-#define BUILDING_CURL_NTLM_C
-
 #include "urldata.h"
-#include "non-ascii.h"
+#include "non-ascii.h"  /* for Curl_convert_... prototypes */
 #include "sendf.h"
 #include "select.h"
 #include "rawstr.h"
 #include "curl_base64.h"
 #include "curl_ntlm.h"
+#include "curl_ntlm_msgs.h"
+#include "curl_ntlm_wb.h"
 #include "url.h"
 #include "strerror.h"
 #include "curl_gethostname.h"
 #define _MPRINTF_REPLACE /* use our functions only */
 #include <curl/mprintf.h>
 
-#ifdef USE_SSLEAY
-#include "ssluse.h"
-#    ifdef USE_OPENSSL
-#      include <openssl/des.h>
-#      ifndef OPENSSL_NO_MD4
-#        include <openssl/md4.h>
-#      endif
-#      include <openssl/md5.h>
-#      include <openssl/ssl.h>
-#      include <openssl/rand.h>
-#    else
-#      include <des.h>
-#      ifndef OPENSSL_NO_MD4
-#        include <md4.h>
-#      endif
-#      include <md5.h>
-#      include <ssl.h>
-#      include <rand.h>
-#    endif
-
-#ifndef OPENSSL_VERSION_NUMBER
-#error "OPENSSL_VERSION_NUMBER not defined"
-#endif
-
-#ifdef OPENSSL_NO_MD4
-/* This requires MD4, but OpenSSL was compiled without it */
-#define USE_NTRESPONSES 0
-#define USE_NTLM2SESSION 0
-#endif
-
-#elif defined(USE_GNUTLS)
-
-#include "gtls.h"
-#include <gcrypt.h>
-
-#define MD5_DIGEST_LENGTH 16
-#define MD4_DIGEST_LENGTH 16
-
-#elif defined(USE_NSS)
-
-#include "curl_md4.h"
+#if defined(USE_NSS)
 #include "nssg.h"
-#include <nss.h>
-#include <pk11pub.h>
-#include <hasht.h>
-#define MD5_DIGEST_LENGTH MD5_LENGTH
-
 #elif defined(USE_WINDOWS_SSPI)
-
 #include "curl_sspi.h"
-
-#else
-#    error "Can't compile NTLM support without a crypto library."
-#endif
-
-#ifndef USE_NTRESPONSES
-/* Define this to make the type-3 message include the NT response message */
-#define USE_NTRESPONSES 1
-
-/* Define this to make the type-3 message include the NTLM2Session response
-   message, requires USE_NTRESPONSES. */
-#define USE_NTLM2SESSION 1
 #endif
 
-#include "curl_ntlm_core.h"
-
 /* The last #include file should be: */
 #include "memdebug.h"
 
-/* Hostname buffer size */
-#define HOSTNAME_MAX 1024
-
-/* "NTLMSSP" signature is always in ASCII regardless of the platform */
-#define NTLMSSP_SIGNATURE "\x4e\x54\x4c\x4d\x53\x53\x50"
-
-#define SHORTPAIR(x) ((x) & 0xff), (((x) >> 8) & 0xff)
-#define LONGQUARTET(x) ((x) & 0xff), (((x) >> 8) & 0xff), \
-  (((x) >> 16) & 0xff), (((x) >> 24) & 0xff)
-
 #if DEBUG_ME
 # define DEBUG_OUT(x) x
-static void ntlm_print_flags(FILE *handle, unsigned long flags)
-{
-  if(flags & NTLMFLAG_NEGOTIATE_UNICODE)
-    fprintf(handle, "NTLMFLAG_NEGOTIATE_UNICODE ");
-  if(flags & NTLMFLAG_NEGOTIATE_OEM)
-    fprintf(handle, "NTLMFLAG_NEGOTIATE_OEM ");
-  if(flags & NTLMFLAG_REQUEST_TARGET)
-    fprintf(handle, "NTLMFLAG_REQUEST_TARGET ");
-  if(flags & (1<<3))
-    fprintf(handle, "NTLMFLAG_UNKNOWN_3 ");
-  if(flags & NTLMFLAG_NEGOTIATE_SIGN)
-    fprintf(handle, "NTLMFLAG_NEGOTIATE_SIGN ");
-  if(flags & NTLMFLAG_NEGOTIATE_SEAL)
-    fprintf(handle, "NTLMFLAG_NEGOTIATE_SEAL ");
-  if(flags & NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE)
-    fprintf(handle, "NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE ");
-  if(flags & NTLMFLAG_NEGOTIATE_LM_KEY)
-    fprintf(handle, "NTLMFLAG_NEGOTIATE_LM_KEY ");
-  if(flags & NTLMFLAG_NEGOTIATE_NETWARE)
-    fprintf(handle, "NTLMFLAG_NEGOTIATE_NETWARE ");
-  if(flags & NTLMFLAG_NEGOTIATE_NTLM_KEY)
-    fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM_KEY ");
-  if(flags & (1<<10))
-    fprintf(handle, "NTLMFLAG_UNKNOWN_10 ");
-  if(flags & NTLMFLAG_NEGOTIATE_ANONYMOUS)
-    fprintf(handle, "NTLMFLAG_NEGOTIATE_ANONYMOUS ");
-  if(flags & NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED)
-    fprintf(handle, "NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED ");
-  if(flags & NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED)
-    fprintf(handle, "NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED ");
-  if(flags & NTLMFLAG_NEGOTIATE_LOCAL_CALL)
-    fprintf(handle, "NTLMFLAG_NEGOTIATE_LOCAL_CALL ");
-  if(flags & NTLMFLAG_NEGOTIATE_ALWAYS_SIGN)
-    fprintf(handle, "NTLMFLAG_NEGOTIATE_ALWAYS_SIGN ");
-  if(flags & NTLMFLAG_TARGET_TYPE_DOMAIN)
-    fprintf(handle, "NTLMFLAG_TARGET_TYPE_DOMAIN ");
-  if(flags & NTLMFLAG_TARGET_TYPE_SERVER)
-    fprintf(handle, "NTLMFLAG_TARGET_TYPE_SERVER ");
-  if(flags & NTLMFLAG_TARGET_TYPE_SHARE)
-    fprintf(handle, "NTLMFLAG_TARGET_TYPE_SHARE ");
-  if(flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY)
-    fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM2_KEY ");
-  if(flags & NTLMFLAG_REQUEST_INIT_RESPONSE)
-    fprintf(handle, "NTLMFLAG_REQUEST_INIT_RESPONSE ");
-  if(flags & NTLMFLAG_REQUEST_ACCEPT_RESPONSE)
-    fprintf(handle, "NTLMFLAG_REQUEST_ACCEPT_RESPONSE ");
-  if(flags & NTLMFLAG_REQUEST_NONNT_SESSION_KEY)
-    fprintf(handle, "NTLMFLAG_REQUEST_NONNT_SESSION_KEY ");
-  if(flags & NTLMFLAG_NEGOTIATE_TARGET_INFO)
-    fprintf(handle, "NTLMFLAG_NEGOTIATE_TARGET_INFO ");
-  if(flags & (1<<24))
-    fprintf(handle, "NTLMFLAG_UNKNOWN_24 ");
-  if(flags & (1<<25))
-    fprintf(handle, "NTLMFLAG_UNKNOWN_25 ");
-  if(flags & (1<<26))
-    fprintf(handle, "NTLMFLAG_UNKNOWN_26 ");
-  if(flags & (1<<27))
-    fprintf(handle, "NTLMFLAG_UNKNOWN_27 ");
-  if(flags & (1<<28))
-    fprintf(handle, "NTLMFLAG_UNKNOWN_28 ");
-  if(flags & NTLMFLAG_NEGOTIATE_128)
-    fprintf(handle, "NTLMFLAG_NEGOTIATE_128 ");
-  if(flags & NTLMFLAG_NEGOTIATE_KEY_EXCHANGE)
-    fprintf(handle, "NTLMFLAG_NEGOTIATE_KEY_EXCHANGE ");
-  if(flags & NTLMFLAG_NEGOTIATE_56)
-    fprintf(handle, "NTLMFLAG_NEGOTIATE_56 ");
-}
-
-static void ntlm_print_hex(FILE *handle, const char *buf, size_t len)
-{
-  const char *p = buf;
-  (void)handle;
-  fprintf(stderr, "0x");
-  while(len-- > 0)
-    fprintf(stderr, "%02.2x", (unsigned int)*p++);
-}
 #else
 # define DEBUG_OUT(x)
 #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)
+CURLcode Curl_input_ntlm(struct connectdata *conn,
+                         bool proxy,         /* if proxy or not */
+                         const char *header) /* rest of the www-authenticate:
+                                                header */
 {
-  return ((unsigned int)buf[0]) | ((unsigned int)buf[1] << 8) |
-    ((unsigned int)buf[2] << 16) | ((unsigned int)buf[3] << 24);
-}
-#endif
-
-/*
-  NTLM message structure notes:
-
-  A 'short' is a 'network short', a little-endian 16-bit unsigned value.
-
-  A 'long' is a 'network long', a little-endian, 32-bit unsigned value.
+  /* point to the correct struct with this */
+  struct ntlmdata *ntlm;
+  CURLcode result = CURLE_OK;
 
-  A 'security buffer' represents a triplet used to point to a buffer,
-  consisting of two shorts and one long:
-
-    1. A 'short' containing the length of the buffer content in bytes.
-    2. A 'short' containing the allocated space for the buffer in bytes.
-    3. A 'long' containing the offset to the start of the buffer in bytes,
-       from the beginning of the NTLM message.
-*/
-
-/*
- * Curl_ntlm_decode_type2_message()
- *
- * This is used to decode a ntlm type-2 message received from a: HTTP, SMTP
- * or POP3 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.
- *
- * 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.
- *
- * Returns CURLE_OK on success.
- */
-CURLcode Curl_ntlm_decode_type2_message(struct SessionHandle *data,
-                                        const char* header,
-                                        struct ntlmdata* ntlm)
-{
-#ifndef USE_WINDOWS_SSPI
-  static const char type2_marker[] = { 0x02, 0x00, 0x00, 0x00 };
+#ifdef USE_NSS
+  result = Curl_nss_force_init(conn->data);
+  if(result)
+    return result;
 #endif
 
-  /* NTLM type-2 message structure:
-
-          Index  Description            Content
-            0    NTLMSSP Signature      Null-terminated ASCII "NTLMSSP"
-                                        (0x4e544c4d53535000)
-            8    NTLM Message Type      long (0x02000000)
-           12    Target Name            security buffer
-           20    Flags                  long
-           24    Challenge              8 bytes
-          (32)   Context                8 bytes (two consecutive longs) (*)
-          (40)   Target Information     security buffer (*)
-          (48)   OS Version Structure   8 bytes (*)
-  32 (48) (56)   Start of data block    (*)
-                                        (*) -> Optional
-  */
-
-  size_t size = 0;
-  unsigned char *buffer = NULL;
-  CURLcode error;
+  ntlm = proxy ? &conn->proxyntlm : &conn->ntlm;
 
-#if defined(CURL_DISABLE_VERBOSE_STRINGS) || defined(USE_WINDOWS_SSPI)
-  (void)data;
-#endif
+  /* skip initial whitespaces */
+  while(*header && ISSPACE(*header))
+    header++;
 
-  error = Curl_base64_decode(header, &buffer, &size);
-  if(error)
-    return error;
+  if(checkprefix("NTLM", header)) {
+    header += strlen("NTLM");
 
-  if(!buffer) {
-    infof(data, "NTLM handshake failure (unhandled condition)\n");
-    return CURLE_REMOTE_ACCESS_DENIED;
-  }
+    while(*header && ISSPACE(*header))
+      header++;
 
-#ifdef USE_WINDOWS_SSPI
-  ntlm->type_2 = malloc(size + 1);
-  if(ntlm->type_2 == NULL) {
-    free(buffer);
-    return CURLE_OUT_OF_MEMORY;
-  }
-  ntlm->n_type_2 = (unsigned long)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)) {
-    /* This was not a good enough type-2 message */
-    free(buffer);
-    infof(data, "NTLM handshake failure (bad type-2 message)\n");
-    return CURLE_REMOTE_ACCESS_DENIED;
-  }
+    if(*header) {
+      result = Curl_ntlm_decode_type2_message(conn->data, header, ntlm);
+      if(CURLE_OK != result)
+        return result;
 
-  ntlm->flags = readint_le(&buffer[20]);
-  memcpy(ntlm->nonce, &buffer[24], 8);
-
-  DEBUG_OUT({
-    fprintf(stderr, "**** TYPE2 header flags=0x%08.8lx ", ntlm->flags);
-    ntlm_print_flags(stderr, ntlm->flags);
-    fprintf(stderr, "\n                  nonce=");
-    ntlm_print_hex(stderr, (char *)ntlm->nonce, 8);
-    fprintf(stderr, "\n****\n");
-    fprintf(stderr, "**** Header %s\n ", header);
-  });
-#endif
-  free(buffer);
+      ntlm->state = NTLMSTATE_TYPE2; /* We got a type-2 message */
+    }
+    else {
+      if(ntlm->state >= NTLMSTATE_TYPE1) {
+        infof(conn->data, "NTLM handshake failure (internal error)\n");
+        return CURLE_REMOTE_ACCESS_DENIED;
+      }
 
-  return CURLE_OK;
-}
-
-#ifdef USE_WINDOWS_SSPI
-void Curl_ntlm_sspi_cleanup(struct ntlmdata *ntlm)
-{
-  if(ntlm->type_2) {
-    free(ntlm->type_2);
-    ntlm->type_2 = NULL;
-  }
-  if(ntlm->has_handles) {
-    s_pSecFn->DeleteSecurityContext(&ntlm->c_handle);
-    s_pSecFn->FreeCredentialsHandle(&ntlm->handle);
-    ntlm->has_handles = 0;
+      ntlm->state = NTLMSTATE_TYPE1; /* We should send away a type-1 */
+    }
   }
-  if(ntlm->p_identity) {
-    if(ntlm->identity.User) free(ntlm->identity.User);
-    if(ntlm->identity.Password) free(ntlm->identity.Password);
-    if(ntlm->identity.Domain) free(ntlm->identity.Domain);
-    ntlm->p_identity = NULL;
-  }
-}
-#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)
-{
-  size_t i;
-  for(i = 0; i < length; i++) {
-    dest[2 * i] = (unsigned char)src[i];
-    dest[2 * i + 1] = '\0';
-  }
+  return result;
 }
-#endif
 
 /*
- * Curl_ntlm_create_type1_message()
- *
- * This is used to generate an already encoded NTLM type-1 message ready
- * for sending to the recipient, be it a: HTTP, SMTP or POP3 server,
- * using the appropriate compile time crypo API.
- *
- * Parameters:
- *
- * userp   [in]     - The user name in the format User or Domain\User.
- * passdwp [in]     - The user's password.
- * ntlm    [in/out] - The ntlm data struct being used and modified.
- * outptr  [in/out] - The adress where a pointer to newly allocated memory
- *                    holding the result will be stored upon completion.
- *
- * Returns CURLE_OK on success.
+ * This is for creating ntlm header output
  */
-CURLcode Curl_ntlm_create_type1_message(const char *userp,
-                                        const char *passwdp,
-                                        struct ntlmdata *ntlm,
-                                        char **outptr)
+CURLcode Curl_output_ntlm(struct connectdata *conn,
+                          bool proxy)
 {
-  /* NTLM type-1 message structure:
-
-       Index  Description            Content
-         0    NTLMSSP Signature      Null-terminated ASCII "NTLMSSP"
-                                     (0x4e544c4d53535000)
-         8    NTLM Message Type      long (0x01000000)
-        12    Flags                  long
-       (16)   Supplied Domain        security buffer (*)
-       (24)   Supplied Workstation   security buffer (*)
-       (32)   OS Version Structure   8 bytes (*)
-  (32) (40)   Start of data block    (*)
-                                     (*) -> Optional
-  */
-
-  unsigned char ntlmbuf[NTLM_BUFSIZE];
-  size_t base64_sz = 0;
-  size_t size;
-
-#ifdef USE_WINDOWS_SSPI
-
-  SecBuffer buf;
-  SecBufferDesc desc;
-  SECURITY_STATUS status;
-  ULONG attrs;
-  const char *dest = "";
-  const char *user;
-  const char *domain = "";
-  size_t userlen = 0;
-  size_t domlen = 0;
-  size_t passwdlen = 0;
-  TimeStamp tsDummy; /* For Windows 9x compatibility of SSPI calls */
-
-  Curl_ntlm_sspi_cleanup(ntlm);
-
-  user = strchr(userp, '\\');
-  if(!user)
-    user = strchr(userp, '/');
-
-  if(user) {
-    domain = userp;
-    domlen = user - userp;
-    user++;
-  }
-  else {
-    user = userp;
-    domain = "";
-    domlen = 0;
-  }
-
-  if(user)
-    userlen = strlen(user);
-
-  if(passwdp)
-    passwdlen = strlen(passwdp);
-
-  if(userlen > 0) {
-    /* note: initialize all of this before doing the mallocs so that
-     * it can be cleaned up later without leaking memory.
-     */
-    ntlm->p_identity = &ntlm->identity;
-    memset(ntlm->p_identity, 0, sizeof(*ntlm->p_identity));
-    if((ntlm->identity.User = (unsigned char *)strdup(user)) == NULL)
-      return CURLE_OUT_OF_MEMORY;
-
-    ntlm->identity.UserLength = (unsigned long)userlen;
-    if((ntlm->identity.Password = (unsigned char *)strdup(passwdp)) == NULL)
-      return CURLE_OUT_OF_MEMORY;
-
-    ntlm->identity.PasswordLength = (unsigned long)strlen(passwdp);
-    if((ntlm->identity.Domain = malloc(domlen + 1)) == NULL)
-      return CURLE_OUT_OF_MEMORY;
-
-    strncpy((char *)ntlm->identity.Domain, domain, domlen);
-    ntlm->identity.Domain[domlen] = '\0';
-    ntlm->identity.DomainLength = (unsigned long)domlen;
-    ntlm->identity.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
-  }
-  else
-    ntlm->p_identity = NULL;
-
-  status = s_pSecFn->AcquireCredentialsHandleA(NULL, (void *)"NTLM",
-                                               SECPKG_CRED_OUTBOUND, NULL,
-                                               ntlm->p_identity, NULL, NULL,
-                                               &ntlm->handle, &tsDummy);
-  if(status != SEC_E_OK)
-    return CURLE_OUT_OF_MEMORY;
+  char *base64 = NULL;
+  CURLcode error;
 
-  desc.ulVersion = SECBUFFER_VERSION;
-  desc.cBuffers  = 1;
-  desc.pBuffers  = &buf;
-  buf.cbBuffer   = NTLM_BUFSIZE;
-  buf.BufferType = SECBUFFER_TOKEN;
-  buf.pvBuffer   = ntlmbuf;
-
-  status = s_pSecFn->InitializeSecurityContextA(&ntlm->handle, NULL,
-                                                (void *)dest,
-                                                ISC_REQ_CONFIDENTIALITY |
-                                                ISC_REQ_REPLAY_DETECT |
-                                                ISC_REQ_CONNECTION,
-                                                0, SECURITY_NETWORK_DREP,
-                                                NULL, 0,
-                                                &ntlm->c_handle, &desc,
-                                                &attrs, &tsDummy);
-
-  if(status == SEC_I_COMPLETE_AND_CONTINUE ||
-     status == SEC_I_CONTINUE_NEEDED)
-    s_pSecFn->CompleteAuthToken(&ntlm->c_handle, &desc);
-  else if(status != SEC_E_OK) {
-    s_pSecFn->FreeCredentialsHandle(&ntlm->handle);
-    return CURLE_RECV_ERROR;
-  }
+  /* 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;
 
-  ntlm->has_handles = 1;
-  size = buf.cbBuffer;
+  /* point to the name and password for this */
+  const char *userp;
+  const char *passwdp;
 
-#else
+  /* point to the correct struct with this */
+  struct ntlmdata *ntlm;
+  struct auth *authp;
 
-  const char *host = "";              /* empty */
-  const char *domain = "";            /* empty */
-  size_t hostlen = 0;
-  size_t domlen = 0;
-  size_t hostoff = 0;
-  size_t domoff = hostoff + hostlen;  /* This is 0: remember that host and
-                                         domain are empty */
-  (void)userp;
-  (void)passwdp;
-  (void)ntlm;
-
-#if USE_NTLM2SESSION
-#define NTLM2FLAG NTLMFLAG_NEGOTIATE_NTLM2_KEY
-#else
-#define NTLM2FLAG 0
-#endif
-  snprintf((char *)ntlmbuf, NTLM_BUFSIZE,
-           NTLMSSP_SIGNATURE "%c"
-           "\x01%c%c%c" /* 32-bit type = 1 */
-           "%c%c%c%c"   /* 32-bit NTLM flag field */
-           "%c%c"       /* domain length */
-           "%c%c"       /* domain allocated space */
-           "%c%c"       /* domain name offset */
-           "%c%c"       /* 2 zeroes */
-           "%c%c"       /* host length */
-           "%c%c"       /* host allocated space */
-           "%c%c"       /* host name offset */
-           "%c%c"       /* 2 zeroes */
-           "%s"         /* host name */
-           "%s",        /* domain string */
-           0,           /* trailing zero */
-           0, 0, 0,     /* part of type-1 long */
-
-           LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM |
-                       NTLMFLAG_REQUEST_TARGET |
-                       NTLMFLAG_NEGOTIATE_NTLM_KEY |
-                       NTLM2FLAG |
-                       NTLMFLAG_NEGOTIATE_ALWAYS_SIGN),
-           SHORTPAIR(domlen),
-           SHORTPAIR(domlen),
-           SHORTPAIR(domoff),
-           0, 0,
-           SHORTPAIR(hostlen),
-           SHORTPAIR(hostlen),
-           SHORTPAIR(hostoff),
-           0, 0,
-           host,  /* this is empty */
-           domain /* this is empty */);
-
-  /* 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 ",
-            LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM |
-                        NTLMFLAG_REQUEST_TARGET |
-                        NTLMFLAG_NEGOTIATE_NTLM_KEY |
-                        NTLM2FLAG |
-                        NTLMFLAG_NEGOTIATE_ALWAYS_SIGN),
-            NTLMFLAG_NEGOTIATE_OEM |
-            NTLMFLAG_REQUEST_TARGET |
-            NTLMFLAG_NEGOTIATE_NTLM_KEY |
-            NTLM2FLAG |
-            NTLMFLAG_NEGOTIATE_ALWAYS_SIGN);
-    ntlm_print_flags(stderr,
-                     NTLMFLAG_NEGOTIATE_OEM |
-                     NTLMFLAG_REQUEST_TARGET |
-                     NTLMFLAG_NEGOTIATE_NTLM_KEY |
-                     NTLM2FLAG |
-                     NTLMFLAG_NEGOTIATE_ALWAYS_SIGN);
-    fprintf(stderr, "\n****\n");
-  });
-
-  /* Return with binary blob encoded into base64 */
-  return Curl_base64_encode(NULL, (char *)ntlmbuf, size, outptr, &base64_sz);
-}
+  DEBUGASSERT(conn);
+  DEBUGASSERT(conn->data);
 
-/*
- * Curl_ntlm_create_type3_message()
- *
- * This is used to generate an already encoded NTLM type-3 message ready
- * for sending to the recipient, be it a: HTTP, SMTP or POP3 server,
- * using the appropriate compile time crypo API.
- *
- * Parameters:
- *
- * data    [in]     - The session handle.
- * userp   [in]     - The user name in the format User or Domain\User.
- * passdwp [in]     - The user's password.
- * ntlm    [in/out] - The ntlm data struct being used and modified.
- * outptr  [in/out] - The adress where a pointer to newly allocated memory
- *                    holding the result will be stored upon completion.
- *
- * 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)
-{
-  /* NTLM type-3 message structure:
-
-          Index  Description            Content
-            0    NTLMSSP Signature      Null-terminated ASCII "NTLMSSP"
-                                        (0x4e544c4d53535000)
-            8    NTLM Message Type      long (0x03000000)
-           12    LM/LMv2 Response       security buffer
-           20    NTLM/NTLMv2 Response   security buffer
-           28    Target Name            security buffer
-           36    User Name              security buffer
-           44    Workstation Name       security buffer
-          (52)   Session Key            security buffer (*)
-          (60)   Flags                  long (*)
-          (64)   OS Version Structure   8 bytes (*)
-  52 (64) (72)   Start of data block
-                                          (*) -> Optional
-  */
-
-  unsigned char ntlmbuf[NTLM_BUFSIZE];
-  size_t base64_sz = 0;
-  size_t size;
-
-#ifdef USE_WINDOWS_SSPI
-  const char *dest = "";
-  SecBuffer type_2;
-  SecBuffer type_3;
-  SecBufferDesc type_2_desc;
-  SecBufferDesc type_3_desc;
-  SECURITY_STATUS status;
-  ULONG attrs;
-  TimeStamp tsDummy; /* For Windows 9x compatibility of SSPI calls */
-
-  (void)passwdp;
-  (void)userp;
-  (void)data;
-
-  type_2_desc.ulVersion = type_3_desc.ulVersion  = SECBUFFER_VERSION;
-  type_2_desc.cBuffers  = type_3_desc.cBuffers   = 1;
-  type_2_desc.pBuffers  = &type_2;
-  type_3_desc.pBuffers  = &type_3;
-
-  type_2.BufferType = SECBUFFER_TOKEN;
-  type_2.pvBuffer   = ntlm->type_2;
-  type_2.cbBuffer   = ntlm->n_type_2;
-  type_3.BufferType = SECBUFFER_TOKEN;
-  type_3.pvBuffer   = ntlmbuf;
-  type_3.cbBuffer   = NTLM_BUFSIZE;
-
-  status = s_pSecFn->InitializeSecurityContextA(&ntlm->handle,
-                                                &ntlm->c_handle,
-                                                (void *)dest,
-                                                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.cbBuffer;
-
-  Curl_ntlm_sspi_cleanup(ntlm);
-
-#else
-  int lmrespoff;
-  unsigned char lmresp[24]; /* fixed-size */
-#if USE_NTRESPONSES
-  int ntrespoff;
-  unsigned char ntresp[24]; /* fixed-size */
+#ifdef USE_NSS
+  if(CURLE_OK != Curl_nss_force_init(conn->data))
+    return CURLE_OUT_OF_MEMORY;
 #endif
-  bool unicode = (ntlm->flags & NTLMFLAG_NEGOTIATE_UNICODE) ? TRUE : FALSE;
-  char host[HOSTNAME_MAX + 1] = "";
-  const char *user;
-  const char *domain = "";
-  size_t hostoff = 0;
-  size_t useroff = 0;
-  size_t domoff = 0;
-  size_t hostlen = 0;
-  size_t userlen = 0;
-  size_t domlen = 0;
-  CURLcode res;
-
-  user = strchr(userp, '\\');
-  if(!user)
-    user = strchr(userp, '/');
-
-  if(user) {
-    domain = userp;
-    domlen = (user - domain);
-    user++;
-  }
-  else
-    user = userp;
 
-  if(user)
-    userlen = strlen(user);
-
-  if(Curl_gethostname(host, HOSTNAME_MAX)) {
-    infof(data, "gethostname() failed, continuing without!");
-    hostlen = 0;
+  if(proxy) {
+    allocuserpwd = &conn->allocptr.proxyuserpwd;
+    userp = conn->proxyuser;
+    passwdp = conn->proxypasswd;
+    ntlm = &conn->proxyntlm;
+    authp = &conn->data->state.authproxy;
   }
   else {
-    /* If the workstation if configured with a full DNS name (i.e.
-     * workstation.somewhere.net) gethostname() returns the fully qualified
-     * name, which NTLM doesn't like.
-     */
-    char *dot = strchr(host, '.');
-    if(dot)
-      *dot = '\0';
-    hostlen = strlen(host);
-  }
-
-  if(unicode) {
-    domlen = domlen * 2;
-    userlen = userlen * 2;
-    hostlen = hostlen * 2;
+    allocuserpwd = &conn->allocptr.userpwd;
+    userp = conn->user;
+    passwdp = conn->passwd;
+    ntlm = &conn->ntlm;
+    authp = &conn->data->state.authhost;
   }
+  authp->done = FALSE;
 
-#if 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];
-    unsigned char tmp[0x18];
-    unsigned char md5sum[MD5_DIGEST_LENGTH];
-    unsigned char entropy[8];
-
-    /* Need to create 8 bytes random data */
-#ifdef USE_SSLEAY
-    MD5_CTX MD5pw;
-    Curl_ossl_seed(data); /* Initiate the seed if not already done */
-    RAND_bytes(entropy, 8);
-#elif defined(USE_GNUTLS)
-    gcry_md_hd_t MD5pw;
-    Curl_gtls_seed(data); /* Initiate the seed if not already done */
-    gcry_randomize(entropy, 8, GCRY_STRONG_RANDOM);
-#elif defined(USE_NSS)
-    PK11Context *MD5pw;
-    unsigned int outlen;
-    Curl_nss_seed(data);  /* Initiate the seed if not already done */
-    PK11_GenerateRandom(entropy, 8);
-#endif
-
-    /* 8 bytes random data as challenge in lmresp */
-    memcpy(lmresp, entropy, 8);
-
-    /* Pad with zeros */
-    memset(lmresp + 8, 0, 0x10);
-
-    /* Fill tmp with challenge(nonce?) + entropy */
-    memcpy(tmp, &ntlm->nonce[0], 8);
-    memcpy(tmp + 8, entropy, 8);
-
-#ifdef USE_SSLEAY
-    MD5_Init(&MD5pw);
-    MD5_Update(&MD5pw, tmp, 16);
-    MD5_Final(md5sum, &MD5pw);
-#elif defined(USE_GNUTLS)
-    gcry_md_open(&MD5pw, GCRY_MD_MD5, 0);
-    gcry_md_write(MD5pw, tmp, MD5_DIGEST_LENGTH);
-    memcpy(md5sum, gcry_md_read (MD5pw, 0), MD5_DIGEST_LENGTH);
-    gcry_md_close(MD5pw);
-#elif defined(USE_NSS)
-    MD5pw = PK11_CreateDigestContext(SEC_OID_MD5);
-    PK11_DigestOp(MD5pw, tmp, 16);
-    PK11_DigestFinal(MD5pw, md5sum, &outlen, MD5_DIGEST_LENGTH);
-    PK11_DestroyContext(MD5pw, PR_TRUE);
-#endif
+  /* not set means empty */
+  if(!userp)
+    userp = "";
 
-    /* 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;
-    Curl_ntlm_core_lm_resp(ntbuffer, md5sum, ntresp);
+  if(!passwdp)
+    passwdp = "";
 
-    /* End of NTLM2 Session code */
+#ifdef USE_WINDOWS_SSPI
+  if(s_hSecDll == NULL) {
+    /* not thread safe and leaks - use curl_global_init() to avoid */
+    CURLcode err = Curl_sspi_global_init();
+    if(s_hSecDll == NULL)
+      return err;
+  }
+#endif
+
+  switch(ntlm->state) {
+  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);
+    if(error)
+      return error;
+
+    if(base64) {
+      Curl_safefree(*allocuserpwd);
+      *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
+                              proxy ? "Proxy-" : "",
+                              base64);
+      DEBUG_OUT(fprintf(stderr, "**** Header %s\n ", *allocuserpwd));
+      free(base64);
+    }
+    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);
+    if(error)
+      return error;
+
+    if(base64) {
+      Curl_safefree(*allocuserpwd);
+      *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
+                              proxy ? "Proxy-" : "",
+                              base64);
+      DEBUG_OUT(fprintf(stderr, "**** %s\n ", *allocuserpwd));
+      free(base64);
+
+      ntlm->state = NTLMSTATE_TYPE3; /* we send a type-3 */
+      authp->done = TRUE;
+    }
+    break;
+
+  case NTLMSTATE_TYPE3:
+    /* connection is already authenticated,
+     * don't send a header in future requests */
+    if(*allocuserpwd) {
+      free(*allocuserpwd);
+      *allocuserpwd = NULL;
+    }
+    authp->done = TRUE;
+    break;
   }
-  else
-#endif
-  {
 
-#if USE_NTRESPONSES
-    unsigned char ntbuffer[0x18];
-#endif
-    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;
-    Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], ntresp);
-#endif
-
-    Curl_ntlm_core_mk_lm_hash(data, passwdp, lmbuffer);
-    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 */
-  }
+  return CURLE_OK;
+}
 
-  lmrespoff = 64; /* size of the message header */
-#if USE_NTRESPONSES
-  ntrespoff = lmrespoff + 0x18;
-  domoff = ntrespoff + 0x18;
-#else
-  domoff = lmrespoff + 0x18;
-#endif
-  useroff = domoff + domlen;
-  hostoff = useroff + userlen;
-
-  /* Create the big type-3 message binary blob */
-  size = snprintf((char *)ntlmbuf, NTLM_BUFSIZE,
-                  NTLMSSP_SIGNATURE "%c"
-                  "\x03%c%c%c"  /* 32-bit type = 3 */
-
-                  "%c%c"  /* LanManager length */
-                  "%c%c"  /* LanManager allocated space */
-                  "%c%c"  /* LanManager offset */
-                  "%c%c"  /* 2 zeroes */
-
-                  "%c%c"  /* NT-response length */
-                  "%c%c"  /* NT-response allocated space */
-                  "%c%c"  /* NT-response offset */
-                  "%c%c"  /* 2 zeroes */
-
-                  "%c%c"  /* domain length */
-                  "%c%c"  /* domain allocated space */
-                  "%c%c"  /* domain name offset */
-                  "%c%c"  /* 2 zeroes */
-
-                  "%c%c"  /* user length */
-                  "%c%c"  /* user allocated space */
-                  "%c%c"  /* user offset */
-                  "%c%c"  /* 2 zeroes */
-
-                  "%c%c"  /* host length */
-                  "%c%c"  /* host allocated space */
-                  "%c%c"  /* host offset */
-                  "%c%c"  /* 2 zeroes */
-
-                  "%c%c"  /* session key length (unknown purpose) */
-                  "%c%c"  /* session key allocated space (unknown purpose) */
-                  "%c%c"  /* session key offset (unknown purpose) */
-                  "%c%c"  /* 2 zeroes */
-
-                  "%c%c%c%c",  /* flags */
-
-                  /* domain string */
-                  /* user string */
-                  /* host string */
-                  /* LanManager response */
-                  /* NT response */
-
-                  0,                /* zero termination */
-                  0, 0, 0,          /* type-3 long, the 24 upper bits */
-
-                  SHORTPAIR(0x18),  /* LanManager response length, twice */
-                  SHORTPAIR(0x18),
-                  SHORTPAIR(lmrespoff),
-                  0x0, 0x0,
-
-#if USE_NTRESPONSES
-                  SHORTPAIR(0x18),  /* NT-response length, twice */
-                  SHORTPAIR(0x18),
-                  SHORTPAIR(ntrespoff),
-                  0x0, 0x0,
+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
-                  0x0, 0x0,
-                  0x0, 0x0,
-                  0x0, 0x0,
-                  0x0, 0x0,
+  (void)conn;
 #endif
-                  SHORTPAIR(domlen),
-                  SHORTPAIR(domlen),
-                  SHORTPAIR(domoff),
-                  0x0, 0x0,
-
-                  SHORTPAIR(userlen),
-                  SHORTPAIR(userlen),
-                  SHORTPAIR(useroff),
-                  0x0, 0x0,
-
-                  SHORTPAIR(hostlen),
-                  SHORTPAIR(hostlen),
-                  SHORTPAIR(hostoff),
-                  0x0, 0x0,
-
-                  0x0, 0x0,
-                  0x0, 0x0,
-                  0x0, 0x0,
-                  0x0, 0x0,
-
-                  LONGQUARTET(ntlm->flags));
-
-  DEBUGASSERT(size == 64);
-  DEBUGASSERT(size == (size_t)lmrespoff);
-
-  /* We append the binary hashes */
-  if(size < (NTLM_BUFSIZE - 0x18)) {
-    memcpy(&ntlmbuf[size], lmresp, 0x18);
-    size += 0x18;
-  }
-
-  DEBUG_OUT({
-    fprintf(stderr, "**** TYPE3 header lmresp=");
-    ntlm_print_hex(stderr, (char *)&ntlmbuf[lmrespoff], 0x18);
-  });
-
-#if USE_NTRESPONSES
-  if(size < (NTLM_BUFSIZE - 0x18)) {
-    DEBUGASSERT(size == (size_t)ntrespoff);
-    memcpy(&ntlmbuf[size], ntresp, 0x18);
-    size += 0x18;
-  }
-
-  DEBUG_OUT({
-    fprintf(stderr, "\n   ntresp=");
-    ntlm_print_hex(stderr, (char *)&ntlmbuf[ntrespoff], 0x18);
-  });
-
-#endif
-
-  DEBUG_OUT({
-    fprintf(stderr, "\n   flags=0x%02.2x%02.2x%02.2x%02.2x 0x%08.8x ",
-            LONGQUARTET(ntlm->flags), ntlm->flags);
-    ntlm_print_flags(stderr, ntlm->flags);
-    fprintf(stderr, "\n****\n");
-  });
-
-  /* Make sure that the domain, user and host strings fit in the
-     buffer before we copy them there. */
-  if(size + userlen + domlen + hostlen >= NTLM_BUFSIZE) {
-    failf(data, "user + domain + host name too big");
-    return CURLE_OUT_OF_MEMORY;
-  }
-
-  DEBUGASSERT(size == domoff);
-  if(unicode)
-    unicodecpy(&ntlmbuf[size], domain, domlen / 2);
-  else
-    memcpy(&ntlmbuf[size], domain, domlen);
-
-  size += domlen;
-
-  DEBUGASSERT(size == useroff);
-  if(unicode)
-    unicodecpy(&ntlmbuf[size], user, userlen / 2);
-  else
-    memcpy(&ntlmbuf[size], user, userlen);
-
-  size += userlen;
-
-  DEBUGASSERT(size == hostoff);
-  if(unicode)
-    unicodecpy(&ntlmbuf[size], host, hostlen / 2);
-  else
-    memcpy(&ntlmbuf[size], host, hostlen);
-
-  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)
-    return CURLE_CONV_FAILED;
-
-#endif
-
-  /* Return with binary blob encoded into base64 */
-  return Curl_base64_encode(NULL, (char *)ntlmbuf, size, outptr, &base64_sz);
 }
 
 #endif /* USE_NTLM */
index fb6cad764aac928d204dee5720867d636fc43dbf..008eb31e87ddd2e99a7bf3767707108f37c12118 100644 (file)
 
 #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);
+/* this is for ntlm header input */
+CURLcode Curl_input_ntlm(struct connectdata *conn, bool proxy,
+                         const char *header);
 
-/* 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);
+/* this is for creating ntlm header output */
+CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy);
 
-/* This is to decode a NTLM type-2 message */
-CURLcode Curl_ntlm_decode_type2_message(struct SessionHandle *data,
-                                        const char* header,
-                                        struct ntlmdata* ntlm);
+void Curl_http_ntlm_cleanup(struct connectdata *conn);
 
-/* This is to clean up the ntlm data structure */
-#ifdef USE_WINDOWS_SSPI
-void Curl_ntlm_sspi_cleanup(struct ntlmdata *ntlm);
-#endif
-
-/* NTLM buffer fixed size, large enough for long user + host + domain */
-#define NTLM_BUFSIZE 1024
-
-/* Stuff only required for curl_ntlm.c */
-#ifdef BUILDING_CURL_NTLM_C
-
-/* Flag bits definitions based on http://davenport.sourceforge.net/ntlm.html */
-
-#define NTLMFLAG_NEGOTIATE_UNICODE               (1<<0)
-/* Indicates that Unicode strings are supported for use in security buffer
-   data. */
-
-#define NTLMFLAG_NEGOTIATE_OEM                   (1<<1)
-/* Indicates that OEM strings are supported for use in security buffer data. */
-
-#define NTLMFLAG_REQUEST_TARGET                  (1<<2)
-/* Requests that the server's authentication realm be included in the Type 2
-   message. */
-
-/* unknown (1<<3) */
-#define NTLMFLAG_NEGOTIATE_SIGN                  (1<<4)
-/* Specifies that authenticated communication between the client and server
-   should carry a digital signature (message integrity). */
-
-#define NTLMFLAG_NEGOTIATE_SEAL                  (1<<5)
-/* Specifies that authenticated communication between the client and server
-   should be encrypted (message confidentiality). */
-
-#define NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE        (1<<6)
-/* Indicates that datagram authentication is being used. */
-
-#define NTLMFLAG_NEGOTIATE_LM_KEY                (1<<7)
-/* Indicates that the LAN Manager session key should be used for signing and
-   sealing authenticated communications. */
-
-#define NTLMFLAG_NEGOTIATE_NETWARE               (1<<8)
-/* unknown purpose */
-
-#define NTLMFLAG_NEGOTIATE_NTLM_KEY              (1<<9)
-/* Indicates that NTLM authentication is being used. */
-
-/* unknown (1<<10) */
-
-#define NTLMFLAG_NEGOTIATE_ANONYMOUS             (1<<11)
-/* Sent by the client in the Type 3 message to indicate that an anonymous
-   context has been established. This also affects the response fields. */
-
-#define NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED       (1<<12)
-/* Sent by the client in the Type 1 message to indicate that a desired
-   authentication realm is included in the message. */
+#else
 
-#define NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED  (1<<13)
-/* Sent by the client in the Type 1 message to indicate that the client
-   workstation's name is included in the message. */
+#define Curl_http_ntlm_cleanup(a)
 
-#define NTLMFLAG_NEGOTIATE_LOCAL_CALL            (1<<14)
-/* Sent by the server to indicate that the server and client are on the same
-   machine. Implies that the client may use a pre-established local security
-   context rather than responding to the challenge. */
-
-#define NTLMFLAG_NEGOTIATE_ALWAYS_SIGN           (1<<15)
-/* Indicates that authenticated communication between the client and server
-   should be signed with a "dummy" signature. */
-
-#define NTLMFLAG_TARGET_TYPE_DOMAIN              (1<<16)
-/* Sent by the server in the Type 2 message to indicate that the target
-   authentication realm is a domain. */
-
-#define NTLMFLAG_TARGET_TYPE_SERVER              (1<<17)
-/* Sent by the server in the Type 2 message to indicate that the target
-   authentication realm is a server. */
-
-#define NTLMFLAG_TARGET_TYPE_SHARE               (1<<18)
-/* Sent by the server in the Type 2 message to indicate that the target
-   authentication realm is a share. Presumably, this is for share-level
-   authentication. Usage is unclear. */
-
-#define NTLMFLAG_NEGOTIATE_NTLM2_KEY             (1<<19)
-/* Indicates that the NTLM2 signing and sealing scheme should be used for
-   protecting authenticated communications. */
-
-#define NTLMFLAG_REQUEST_INIT_RESPONSE           (1<<20)
-/* unknown purpose */
-
-#define NTLMFLAG_REQUEST_ACCEPT_RESPONSE         (1<<21)
-/* unknown purpose */
-
-#define NTLMFLAG_REQUEST_NONNT_SESSION_KEY       (1<<22)
-/* unknown purpose */
-
-#define NTLMFLAG_NEGOTIATE_TARGET_INFO           (1<<23)
-/* Sent by the server in the Type 2 message to indicate that it is including a
-   Target Information block in the message. */
-
-/* unknown (1<24) */
-/* unknown (1<25) */
-/* unknown (1<26) */
-/* unknown (1<27) */
-/* unknown (1<28) */
-
-#define NTLMFLAG_NEGOTIATE_128                   (1<<29)
-/* Indicates that 128-bit encryption is supported. */
-
-#define NTLMFLAG_NEGOTIATE_KEY_EXCHANGE          (1<<30)
-/* Indicates that the client will provide an encrypted master key in
-   the "Session Key" field of the Type 3 message. */
-
-#define NTLMFLAG_NEGOTIATE_56                    (1<<31)
-/* Indicates that 56-bit encryption is supported. */
-
-#endif /* BUILDING_CURL_NTLM_C */
-
-#endif /* USE_NTLM */
+#endif
 
 #endif /* HEADER_CURL_NTLM_H */
diff --git a/lib/curl_ntlm_msgs.c b/lib/curl_ntlm_msgs.c
new file mode 100644 (file)
index 0000000..732974b
--- /dev/null
@@ -0,0 +1,997 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, 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 "setup.h"
+
+/* NTLM details:
+
+   http://davenport.sourceforge.net/ntlm.html
+   http://www.innovation.ch/java/ntlm.html
+*/
+
+#ifdef USE_NTLM
+
+#define DEBUG_ME 0
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#if (defined(NETWARE) && !defined(__NOVELL_LIBC__))
+#include <netdb.h>
+#endif
+
+#define BUILDING_CURL_NTLM_MSGS_C
+
+#include "urldata.h"
+#include "non-ascii.h"
+#include "sendf.h"
+#include "select.h"
+#include "rawstr.h"
+#include "curl_base64.h"
+#include "curl_ntlm_msgs.h"
+#include "url.h"
+#include "strerror.h"
+#include "curl_gethostname.h"
+#include "curl_memory.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#ifdef USE_SSLEAY
+#include "ssluse.h"
+#    ifdef USE_OPENSSL
+#      include <openssl/des.h>
+#      ifndef OPENSSL_NO_MD4
+#        include <openssl/md4.h>
+#      endif
+#      include <openssl/md5.h>
+#      include <openssl/ssl.h>
+#      include <openssl/rand.h>
+#    else
+#      include <des.h>
+#      ifndef OPENSSL_NO_MD4
+#        include <md4.h>
+#      endif
+#      include <md5.h>
+#      include <ssl.h>
+#      include <rand.h>
+#    endif
+
+#ifndef OPENSSL_VERSION_NUMBER
+#error "OPENSSL_VERSION_NUMBER not defined"
+#endif
+
+#ifdef OPENSSL_NO_MD4
+/* This requires MD4, but OpenSSL was compiled without it */
+#define USE_NTRESPONSES 0
+#define USE_NTLM2SESSION 0
+#endif
+
+#elif defined(USE_GNUTLS)
+
+#include "gtls.h"
+#include <gcrypt.h>
+
+#define MD5_DIGEST_LENGTH 16
+#define MD4_DIGEST_LENGTH 16
+
+#elif defined(USE_NSS)
+
+#include "curl_md4.h"
+#include "nssg.h"
+#include <nss.h>
+#include <pk11pub.h>
+#include <hasht.h>
+#define MD5_DIGEST_LENGTH MD5_LENGTH
+
+#elif defined(USE_WINDOWS_SSPI)
+
+#include "curl_sspi.h"
+
+#else
+#    error "Can't compile NTLM support without a crypto library."
+#endif
+
+#ifndef USE_NTRESPONSES
+/* Define this to make the type-3 message include the NT response message */
+#define USE_NTRESPONSES 1
+
+/* Define this to make the type-3 message include the NTLM2Session response
+   message, requires USE_NTRESPONSES. */
+#define USE_NTLM2SESSION 1
+#endif
+
+#include "curl_ntlm_core.h"
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/* Hostname buffer size */
+#define HOSTNAME_MAX 1024
+
+/* "NTLMSSP" signature is always in ASCII regardless of the platform */
+#define NTLMSSP_SIGNATURE "\x4e\x54\x4c\x4d\x53\x53\x50"
+
+#define SHORTPAIR(x) ((x) & 0xff), (((x) >> 8) & 0xff)
+#define LONGQUARTET(x) ((x) & 0xff), (((x) >> 8) & 0xff), \
+  (((x) >> 16) & 0xff), (((x) >> 24) & 0xff)
+
+#if DEBUG_ME
+# define DEBUG_OUT(x) x
+static void ntlm_print_flags(FILE *handle, unsigned long flags)
+{
+  if(flags & NTLMFLAG_NEGOTIATE_UNICODE)
+    fprintf(handle, "NTLMFLAG_NEGOTIATE_UNICODE ");
+  if(flags & NTLMFLAG_NEGOTIATE_OEM)
+    fprintf(handle, "NTLMFLAG_NEGOTIATE_OEM ");
+  if(flags & NTLMFLAG_REQUEST_TARGET)
+    fprintf(handle, "NTLMFLAG_REQUEST_TARGET ");
+  if(flags & (1<<3))
+    fprintf(handle, "NTLMFLAG_UNKNOWN_3 ");
+  if(flags & NTLMFLAG_NEGOTIATE_SIGN)
+    fprintf(handle, "NTLMFLAG_NEGOTIATE_SIGN ");
+  if(flags & NTLMFLAG_NEGOTIATE_SEAL)
+    fprintf(handle, "NTLMFLAG_NEGOTIATE_SEAL ");
+  if(flags & NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE)
+    fprintf(handle, "NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE ");
+  if(flags & NTLMFLAG_NEGOTIATE_LM_KEY)
+    fprintf(handle, "NTLMFLAG_NEGOTIATE_LM_KEY ");
+  if(flags & NTLMFLAG_NEGOTIATE_NETWARE)
+    fprintf(handle, "NTLMFLAG_NEGOTIATE_NETWARE ");
+  if(flags & NTLMFLAG_NEGOTIATE_NTLM_KEY)
+    fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM_KEY ");
+  if(flags & (1<<10))
+    fprintf(handle, "NTLMFLAG_UNKNOWN_10 ");
+  if(flags & NTLMFLAG_NEGOTIATE_ANONYMOUS)
+    fprintf(handle, "NTLMFLAG_NEGOTIATE_ANONYMOUS ");
+  if(flags & NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED)
+    fprintf(handle, "NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED ");
+  if(flags & NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED)
+    fprintf(handle, "NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED ");
+  if(flags & NTLMFLAG_NEGOTIATE_LOCAL_CALL)
+    fprintf(handle, "NTLMFLAG_NEGOTIATE_LOCAL_CALL ");
+  if(flags & NTLMFLAG_NEGOTIATE_ALWAYS_SIGN)
+    fprintf(handle, "NTLMFLAG_NEGOTIATE_ALWAYS_SIGN ");
+  if(flags & NTLMFLAG_TARGET_TYPE_DOMAIN)
+    fprintf(handle, "NTLMFLAG_TARGET_TYPE_DOMAIN ");
+  if(flags & NTLMFLAG_TARGET_TYPE_SERVER)
+    fprintf(handle, "NTLMFLAG_TARGET_TYPE_SERVER ");
+  if(flags & NTLMFLAG_TARGET_TYPE_SHARE)
+    fprintf(handle, "NTLMFLAG_TARGET_TYPE_SHARE ");
+  if(flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY)
+    fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM2_KEY ");
+  if(flags & NTLMFLAG_REQUEST_INIT_RESPONSE)
+    fprintf(handle, "NTLMFLAG_REQUEST_INIT_RESPONSE ");
+  if(flags & NTLMFLAG_REQUEST_ACCEPT_RESPONSE)
+    fprintf(handle, "NTLMFLAG_REQUEST_ACCEPT_RESPONSE ");
+  if(flags & NTLMFLAG_REQUEST_NONNT_SESSION_KEY)
+    fprintf(handle, "NTLMFLAG_REQUEST_NONNT_SESSION_KEY ");
+  if(flags & NTLMFLAG_NEGOTIATE_TARGET_INFO)
+    fprintf(handle, "NTLMFLAG_NEGOTIATE_TARGET_INFO ");
+  if(flags & (1<<24))
+    fprintf(handle, "NTLMFLAG_UNKNOWN_24 ");
+  if(flags & (1<<25))
+    fprintf(handle, "NTLMFLAG_UNKNOWN_25 ");
+  if(flags & (1<<26))
+    fprintf(handle, "NTLMFLAG_UNKNOWN_26 ");
+  if(flags & (1<<27))
+    fprintf(handle, "NTLMFLAG_UNKNOWN_27 ");
+  if(flags & (1<<28))
+    fprintf(handle, "NTLMFLAG_UNKNOWN_28 ");
+  if(flags & NTLMFLAG_NEGOTIATE_128)
+    fprintf(handle, "NTLMFLAG_NEGOTIATE_128 ");
+  if(flags & NTLMFLAG_NEGOTIATE_KEY_EXCHANGE)
+    fprintf(handle, "NTLMFLAG_NEGOTIATE_KEY_EXCHANGE ");
+  if(flags & NTLMFLAG_NEGOTIATE_56)
+    fprintf(handle, "NTLMFLAG_NEGOTIATE_56 ");
+}
+
+static void ntlm_print_hex(FILE *handle, const char *buf, size_t len)
+{
+  const char *p = buf;
+  (void)handle;
+  fprintf(stderr, "0x");
+  while(len-- > 0)
+    fprintf(stderr, "%02.2x", (unsigned int)*p++);
+}
+#else
+# define DEBUG_OUT(x)
+#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);
+}
+#endif
+
+/*
+  NTLM message structure notes:
+
+  A 'short' is a 'network short', a little-endian 16-bit unsigned value.
+
+  A 'long' is a 'network long', a little-endian, 32-bit unsigned value.
+
+  A 'security buffer' represents a triplet used to point to a buffer,
+  consisting of two shorts and one long:
+
+    1. A 'short' containing the length of the buffer content in bytes.
+    2. A 'short' containing the allocated space for the buffer in bytes.
+    3. A 'long' containing the offset to the start of the buffer in bytes,
+       from the beginning of the NTLM message.
+*/
+
+/*
+ * Curl_ntlm_decode_type2_message()
+ *
+ * This is used to decode a ntlm type-2 message received from a: HTTP, SMTP
+ * or POP3 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.
+ *
+ * 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.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_ntlm_decode_type2_message(struct SessionHandle *data,
+                                        const char* header,
+                                        struct ntlmdata* ntlm)
+{
+#ifndef USE_WINDOWS_SSPI
+  static const char type2_marker[] = { 0x02, 0x00, 0x00, 0x00 };
+#endif
+
+  /* NTLM type-2 message structure:
+
+          Index  Description            Content
+            0    NTLMSSP Signature      Null-terminated ASCII "NTLMSSP"
+                                        (0x4e544c4d53535000)
+            8    NTLM Message Type      long (0x02000000)
+           12    Target Name            security buffer
+           20    Flags                  long
+           24    Challenge              8 bytes
+          (32)   Context                8 bytes (two consecutive longs) (*)
+          (40)   Target Information     security buffer (*)
+          (48)   OS Version Structure   8 bytes (*)
+  32 (48) (56)   Start of data block    (*)
+                                        (*) -> Optional
+  */
+
+  size_t size = 0;
+  unsigned char *buffer = NULL;
+  CURLcode error;
+
+#if defined(CURL_DISABLE_VERBOSE_STRINGS) || defined(USE_WINDOWS_SSPI)
+  (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;
+  }
+
+#ifdef USE_WINDOWS_SSPI
+  ntlm->type_2 = malloc(size + 1);
+  if(ntlm->type_2 == NULL) {
+    free(buffer);
+    return CURLE_OUT_OF_MEMORY;
+  }
+  ntlm->n_type_2 = (unsigned long)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)) {
+    /* This was not a good enough type-2 message */
+    free(buffer);
+    infof(data, "NTLM handshake failure (bad type-2 message)\n");
+    return CURLE_REMOTE_ACCESS_DENIED;
+  }
+
+  ntlm->flags = readint_le(&buffer[20]);
+  memcpy(ntlm->nonce, &buffer[24], 8);
+
+  DEBUG_OUT({
+    fprintf(stderr, "**** TYPE2 header flags=0x%08.8lx ", ntlm->flags);
+    ntlm_print_flags(stderr, ntlm->flags);
+    fprintf(stderr, "\n                  nonce=");
+    ntlm_print_hex(stderr, (char *)ntlm->nonce, 8);
+    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)
+{
+  if(ntlm->type_2) {
+    free(ntlm->type_2);
+    ntlm->type_2 = NULL;
+  }
+  if(ntlm->has_handles) {
+    s_pSecFn->DeleteSecurityContext(&ntlm->c_handle);
+    s_pSecFn->FreeCredentialsHandle(&ntlm->handle);
+    ntlm->has_handles = 0;
+  }
+  if(ntlm->p_identity) {
+    if(ntlm->identity.User) free(ntlm->identity.User);
+    if(ntlm->identity.Password) free(ntlm->identity.Password);
+    if(ntlm->identity.Domain) free(ntlm->identity.Domain);
+    ntlm->p_identity = NULL;
+  }
+}
+#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)
+{
+  size_t i;
+  for(i = 0; i < length; i++) {
+    dest[2 * i] = (unsigned char)src[i];
+    dest[2 * i + 1] = '\0';
+  }
+}
+#endif
+
+/*
+ * Curl_ntlm_create_type1_message()
+ *
+ * This is used to generate an already encoded NTLM type-1 message ready
+ * for sending to the recipient, be it a: HTTP, SMTP or POP3 server,
+ * using the appropriate compile time crypo API.
+ *
+ * Parameters:
+ *
+ * userp   [in]     - The user name in the format User or Domain\User.
+ * passdwp [in]     - The user's password.
+ * ntlm    [in/out] - The ntlm data struct being used and modified.
+ * outptr  [in/out] - The adress where a pointer to newly allocated memory
+ *                    holding the result will be stored upon completion.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_ntlm_create_type1_message(const char *userp,
+                                        const char *passwdp,
+                                        struct ntlmdata *ntlm,
+                                        char **outptr)
+{
+  /* NTLM type-1 message structure:
+
+       Index  Description            Content
+         0    NTLMSSP Signature      Null-terminated ASCII "NTLMSSP"
+                                     (0x4e544c4d53535000)
+         8    NTLM Message Type      long (0x01000000)
+        12    Flags                  long
+       (16)   Supplied Domain        security buffer (*)
+       (24)   Supplied Workstation   security buffer (*)
+       (32)   OS Version Structure   8 bytes (*)
+  (32) (40)   Start of data block    (*)
+                                     (*) -> Optional
+  */
+
+  unsigned char ntlmbuf[NTLM_BUFSIZE];
+  size_t base64_sz = 0;
+  size_t size;
+
+#ifdef USE_WINDOWS_SSPI
+
+  SecBuffer buf;
+  SecBufferDesc desc;
+  SECURITY_STATUS status;
+  ULONG attrs;
+  const char *dest = "";
+  const char *user;
+  const char *domain = "";
+  size_t userlen = 0;
+  size_t domlen = 0;
+  size_t passwdlen = 0;
+  TimeStamp tsDummy; /* For Windows 9x compatibility of SSPI calls */
+
+  Curl_ntlm_sspi_cleanup(ntlm);
+
+  user = strchr(userp, '\\');
+  if(!user)
+    user = strchr(userp, '/');
+
+  if(user) {
+    domain = userp;
+    domlen = user - userp;
+    user++;
+  }
+  else {
+    user = userp;
+    domain = "";
+    domlen = 0;
+  }
+
+  if(user)
+    userlen = strlen(user);
+
+  if(passwdp)
+    passwdlen = strlen(passwdp);
+
+  if(userlen > 0) {
+    /* note: initialize all of this before doing the mallocs so that
+     * it can be cleaned up later without leaking memory.
+     */
+    ntlm->p_identity = &ntlm->identity;
+    memset(ntlm->p_identity, 0, sizeof(*ntlm->p_identity));
+    if((ntlm->identity.User = (unsigned char *)strdup(user)) == NULL)
+      return CURLE_OUT_OF_MEMORY;
+
+    ntlm->identity.UserLength = (unsigned long)userlen;
+    if((ntlm->identity.Password = (unsigned char *)strdup(passwdp)) == NULL)
+      return CURLE_OUT_OF_MEMORY;
+
+    ntlm->identity.PasswordLength = (unsigned long)strlen(passwdp);
+    if((ntlm->identity.Domain = malloc(domlen + 1)) == NULL)
+      return CURLE_OUT_OF_MEMORY;
+
+    strncpy((char *)ntlm->identity.Domain, domain, domlen);
+    ntlm->identity.Domain[domlen] = '\0';
+    ntlm->identity.DomainLength = (unsigned long)domlen;
+    ntlm->identity.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
+  }
+  else
+    ntlm->p_identity = NULL;
+
+  status = s_pSecFn->AcquireCredentialsHandleA(NULL, (void *)"NTLM",
+                                               SECPKG_CRED_OUTBOUND, NULL,
+                                               ntlm->p_identity, NULL, NULL,
+                                               &ntlm->handle, &tsDummy);
+  if(status != SEC_E_OK)
+    return CURLE_OUT_OF_MEMORY;
+
+  desc.ulVersion = SECBUFFER_VERSION;
+  desc.cBuffers  = 1;
+  desc.pBuffers  = &buf;
+  buf.cbBuffer   = NTLM_BUFSIZE;
+  buf.BufferType = SECBUFFER_TOKEN;
+  buf.pvBuffer   = ntlmbuf;
+
+  status = s_pSecFn->InitializeSecurityContextA(&ntlm->handle, NULL,
+                                                (void *)dest,
+                                                ISC_REQ_CONFIDENTIALITY |
+                                                ISC_REQ_REPLAY_DETECT |
+                                                ISC_REQ_CONNECTION,
+                                                0, SECURITY_NETWORK_DREP,
+                                                NULL, 0,
+                                                &ntlm->c_handle, &desc,
+                                                &attrs, &tsDummy);
+
+  if(status == SEC_I_COMPLETE_AND_CONTINUE ||
+     status == SEC_I_CONTINUE_NEEDED)
+    s_pSecFn->CompleteAuthToken(&ntlm->c_handle, &desc);
+  else if(status != SEC_E_OK) {
+    s_pSecFn->FreeCredentialsHandle(&ntlm->handle);
+    return CURLE_RECV_ERROR;
+  }
+
+  ntlm->has_handles = 1;
+  size = buf.cbBuffer;
+
+#else
+
+  const char *host = "";              /* empty */
+  const char *domain = "";            /* empty */
+  size_t hostlen = 0;
+  size_t domlen = 0;
+  size_t hostoff = 0;
+  size_t domoff = hostoff + hostlen;  /* This is 0: remember that host and
+                                         domain are empty */
+  (void)userp;
+  (void)passwdp;
+  (void)ntlm;
+
+#if USE_NTLM2SESSION
+#define NTLM2FLAG NTLMFLAG_NEGOTIATE_NTLM2_KEY
+#else
+#define NTLM2FLAG 0
+#endif
+  snprintf((char *)ntlmbuf, NTLM_BUFSIZE,
+           NTLMSSP_SIGNATURE "%c"
+           "\x01%c%c%c" /* 32-bit type = 1 */
+           "%c%c%c%c"   /* 32-bit NTLM flag field */
+           "%c%c"       /* domain length */
+           "%c%c"       /* domain allocated space */
+           "%c%c"       /* domain name offset */
+           "%c%c"       /* 2 zeroes */
+           "%c%c"       /* host length */
+           "%c%c"       /* host allocated space */
+           "%c%c"       /* host name offset */
+           "%c%c"       /* 2 zeroes */
+           "%s"         /* host name */
+           "%s",        /* domain string */
+           0,           /* trailing zero */
+           0, 0, 0,     /* part of type-1 long */
+
+           LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM |
+                       NTLMFLAG_REQUEST_TARGET |
+                       NTLMFLAG_NEGOTIATE_NTLM_KEY |
+                       NTLM2FLAG |
+                       NTLMFLAG_NEGOTIATE_ALWAYS_SIGN),
+           SHORTPAIR(domlen),
+           SHORTPAIR(domlen),
+           SHORTPAIR(domoff),
+           0, 0,
+           SHORTPAIR(hostlen),
+           SHORTPAIR(hostlen),
+           SHORTPAIR(hostoff),
+           0, 0,
+           host,  /* this is empty */
+           domain /* this is empty */);
+
+  /* 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 ",
+            LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM |
+                        NTLMFLAG_REQUEST_TARGET |
+                        NTLMFLAG_NEGOTIATE_NTLM_KEY |
+                        NTLM2FLAG |
+                        NTLMFLAG_NEGOTIATE_ALWAYS_SIGN),
+            NTLMFLAG_NEGOTIATE_OEM |
+            NTLMFLAG_REQUEST_TARGET |
+            NTLMFLAG_NEGOTIATE_NTLM_KEY |
+            NTLM2FLAG |
+            NTLMFLAG_NEGOTIATE_ALWAYS_SIGN);
+    ntlm_print_flags(stderr,
+                     NTLMFLAG_NEGOTIATE_OEM |
+                     NTLMFLAG_REQUEST_TARGET |
+                     NTLMFLAG_NEGOTIATE_NTLM_KEY |
+                     NTLM2FLAG |
+                     NTLMFLAG_NEGOTIATE_ALWAYS_SIGN);
+    fprintf(stderr, "\n****\n");
+  });
+
+  /* Return with binary blob encoded into base64 */
+  return Curl_base64_encode(NULL, (char *)ntlmbuf, size, outptr, &base64_sz);
+}
+
+/*
+ * Curl_ntlm_create_type3_message()
+ *
+ * This is used to generate an already encoded NTLM type-3 message ready
+ * for sending to the recipient, be it a: HTTP, SMTP or POP3 server,
+ * using the appropriate compile time crypo API.
+ *
+ * Parameters:
+ *
+ * data    [in]     - The session handle.
+ * userp   [in]     - The user name in the format User or Domain\User.
+ * passdwp [in]     - The user's password.
+ * ntlm    [in/out] - The ntlm data struct being used and modified.
+ * outptr  [in/out] - The adress where a pointer to newly allocated memory
+ *                    holding the result will be stored upon completion.
+ *
+ * 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)
+{
+  /* NTLM type-3 message structure:
+
+          Index  Description            Content
+            0    NTLMSSP Signature      Null-terminated ASCII "NTLMSSP"
+                                        (0x4e544c4d53535000)
+            8    NTLM Message Type      long (0x03000000)
+           12    LM/LMv2 Response       security buffer
+           20    NTLM/NTLMv2 Response   security buffer
+           28    Target Name            security buffer
+           36    User Name              security buffer
+           44    Workstation Name       security buffer
+          (52)   Session Key            security buffer (*)
+          (60)   Flags                  long (*)
+          (64)   OS Version Structure   8 bytes (*)
+  52 (64) (72)   Start of data block
+                                          (*) -> Optional
+  */
+
+  unsigned char ntlmbuf[NTLM_BUFSIZE];
+  size_t base64_sz = 0;
+  size_t size;
+
+#ifdef USE_WINDOWS_SSPI
+  const char *dest = "";
+  SecBuffer type_2;
+  SecBuffer type_3;
+  SecBufferDesc type_2_desc;
+  SecBufferDesc type_3_desc;
+  SECURITY_STATUS status;
+  ULONG attrs;
+  TimeStamp tsDummy; /* For Windows 9x compatibility of SSPI calls */
+
+  (void)passwdp;
+  (void)userp;
+  (void)data;
+
+  type_2_desc.ulVersion = type_3_desc.ulVersion  = SECBUFFER_VERSION;
+  type_2_desc.cBuffers  = type_3_desc.cBuffers   = 1;
+  type_2_desc.pBuffers  = &type_2;
+  type_3_desc.pBuffers  = &type_3;
+
+  type_2.BufferType = SECBUFFER_TOKEN;
+  type_2.pvBuffer   = ntlm->type_2;
+  type_2.cbBuffer   = ntlm->n_type_2;
+  type_3.BufferType = SECBUFFER_TOKEN;
+  type_3.pvBuffer   = ntlmbuf;
+  type_3.cbBuffer   = NTLM_BUFSIZE;
+
+  status = s_pSecFn->InitializeSecurityContextA(&ntlm->handle,
+                                                &ntlm->c_handle,
+                                                (void *)dest,
+                                                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.cbBuffer;
+
+  Curl_ntlm_sspi_cleanup(ntlm);
+
+#else
+  int lmrespoff;
+  unsigned char lmresp[24]; /* fixed-size */
+#if USE_NTRESPONSES
+  int ntrespoff;
+  unsigned char ntresp[24]; /* fixed-size */
+#endif
+  bool unicode = (ntlm->flags & NTLMFLAG_NEGOTIATE_UNICODE) ? TRUE : FALSE;
+  char host[HOSTNAME_MAX + 1] = "";
+  const char *user;
+  const char *domain = "";
+  size_t hostoff = 0;
+  size_t useroff = 0;
+  size_t domoff = 0;
+  size_t hostlen = 0;
+  size_t userlen = 0;
+  size_t domlen = 0;
+  CURLcode res;
+
+  user = strchr(userp, '\\');
+  if(!user)
+    user = strchr(userp, '/');
+
+  if(user) {
+    domain = userp;
+    domlen = (user - domain);
+    user++;
+  }
+  else
+    user = userp;
+
+  if(user)
+    userlen = strlen(user);
+
+  if(Curl_gethostname(host, HOSTNAME_MAX)) {
+    infof(data, "gethostname() failed, continuing without!");
+    hostlen = 0;
+  }
+  else {
+    /* If the workstation if configured with a full DNS name (i.e.
+     * workstation.somewhere.net) gethostname() returns the fully qualified
+     * name, which NTLM doesn't like.
+     */
+    char *dot = strchr(host, '.');
+    if(dot)
+      *dot = '\0';
+    hostlen = strlen(host);
+  }
+
+  if(unicode) {
+    domlen = domlen * 2;
+    userlen = userlen * 2;
+    hostlen = hostlen * 2;
+  }
+
+#if 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];
+    unsigned char tmp[0x18];
+    unsigned char md5sum[MD5_DIGEST_LENGTH];
+    unsigned char entropy[8];
+
+    /* Need to create 8 bytes random data */
+#ifdef USE_SSLEAY
+    MD5_CTX MD5pw;
+    Curl_ossl_seed(data); /* Initiate the seed if not already done */
+    RAND_bytes(entropy, 8);
+#elif defined(USE_GNUTLS)
+    gcry_md_hd_t MD5pw;
+    Curl_gtls_seed(data); /* Initiate the seed if not already done */
+    gcry_randomize(entropy, 8, GCRY_STRONG_RANDOM);
+#elif defined(USE_NSS)
+    PK11Context *MD5pw;
+    unsigned int outlen;
+    Curl_nss_seed(data);  /* Initiate the seed if not already done */
+    PK11_GenerateRandom(entropy, 8);
+#endif
+
+    /* 8 bytes random data as challenge in lmresp */
+    memcpy(lmresp, entropy, 8);
+
+    /* Pad with zeros */
+    memset(lmresp + 8, 0, 0x10);
+
+    /* Fill tmp with challenge(nonce?) + entropy */
+    memcpy(tmp, &ntlm->nonce[0], 8);
+    memcpy(tmp + 8, entropy, 8);
+
+#ifdef USE_SSLEAY
+    MD5_Init(&MD5pw);
+    MD5_Update(&MD5pw, tmp, 16);
+    MD5_Final(md5sum, &MD5pw);
+#elif defined(USE_GNUTLS)
+    gcry_md_open(&MD5pw, GCRY_MD_MD5, 0);
+    gcry_md_write(MD5pw, tmp, MD5_DIGEST_LENGTH);
+    memcpy(md5sum, gcry_md_read (MD5pw, 0), MD5_DIGEST_LENGTH);
+    gcry_md_close(MD5pw);
+#elif defined(USE_NSS)
+    MD5pw = PK11_CreateDigestContext(SEC_OID_MD5);
+    PK11_DigestOp(MD5pw, tmp, 16);
+    PK11_DigestFinal(MD5pw, md5sum, &outlen, MD5_DIGEST_LENGTH);
+    PK11_DestroyContext(MD5pw, PR_TRUE);
+#endif
+
+    /* 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;
+    Curl_ntlm_core_lm_resp(ntbuffer, md5sum, ntresp);
+
+    /* End of NTLM2 Session code */
+  }
+  else
+#endif
+  {
+
+#if USE_NTRESPONSES
+    unsigned char ntbuffer[0x18];
+#endif
+    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;
+    Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], ntresp);
+#endif
+
+    Curl_ntlm_core_mk_lm_hash(data, passwdp, lmbuffer);
+    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 */
+  }
+
+  lmrespoff = 64; /* size of the message header */
+#if USE_NTRESPONSES
+  ntrespoff = lmrespoff + 0x18;
+  domoff = ntrespoff + 0x18;
+#else
+  domoff = lmrespoff + 0x18;
+#endif
+  useroff = domoff + domlen;
+  hostoff = useroff + userlen;
+
+  /* Create the big type-3 message binary blob */
+  size = snprintf((char *)ntlmbuf, NTLM_BUFSIZE,
+                  NTLMSSP_SIGNATURE "%c"
+                  "\x03%c%c%c"  /* 32-bit type = 3 */
+
+                  "%c%c"  /* LanManager length */
+                  "%c%c"  /* LanManager allocated space */
+                  "%c%c"  /* LanManager offset */
+                  "%c%c"  /* 2 zeroes */
+
+                  "%c%c"  /* NT-response length */
+                  "%c%c"  /* NT-response allocated space */
+                  "%c%c"  /* NT-response offset */
+                  "%c%c"  /* 2 zeroes */
+
+                  "%c%c"  /* domain length */
+                  "%c%c"  /* domain allocated space */
+                  "%c%c"  /* domain name offset */
+                  "%c%c"  /* 2 zeroes */
+
+                  "%c%c"  /* user length */
+                  "%c%c"  /* user allocated space */
+                  "%c%c"  /* user offset */
+                  "%c%c"  /* 2 zeroes */
+
+                  "%c%c"  /* host length */
+                  "%c%c"  /* host allocated space */
+                  "%c%c"  /* host offset */
+                  "%c%c"  /* 2 zeroes */
+
+                  "%c%c"  /* session key length (unknown purpose) */
+                  "%c%c"  /* session key allocated space (unknown purpose) */
+                  "%c%c"  /* session key offset (unknown purpose) */
+                  "%c%c"  /* 2 zeroes */
+
+                  "%c%c%c%c",  /* flags */
+
+                  /* domain string */
+                  /* user string */
+                  /* host string */
+                  /* LanManager response */
+                  /* NT response */
+
+                  0,                /* zero termination */
+                  0, 0, 0,          /* type-3 long, the 24 upper bits */
+
+                  SHORTPAIR(0x18),  /* LanManager response length, twice */
+                  SHORTPAIR(0x18),
+                  SHORTPAIR(lmrespoff),
+                  0x0, 0x0,
+
+#if USE_NTRESPONSES
+                  SHORTPAIR(0x18),  /* NT-response length, twice */
+                  SHORTPAIR(0x18),
+                  SHORTPAIR(ntrespoff),
+                  0x0, 0x0,
+#else
+                  0x0, 0x0,
+                  0x0, 0x0,
+                  0x0, 0x0,
+                  0x0, 0x0,
+#endif
+                  SHORTPAIR(domlen),
+                  SHORTPAIR(domlen),
+                  SHORTPAIR(domoff),
+                  0x0, 0x0,
+
+                  SHORTPAIR(userlen),
+                  SHORTPAIR(userlen),
+                  SHORTPAIR(useroff),
+                  0x0, 0x0,
+
+                  SHORTPAIR(hostlen),
+                  SHORTPAIR(hostlen),
+                  SHORTPAIR(hostoff),
+                  0x0, 0x0,
+
+                  0x0, 0x0,
+                  0x0, 0x0,
+                  0x0, 0x0,
+                  0x0, 0x0,
+
+                  LONGQUARTET(ntlm->flags));
+
+  DEBUGASSERT(size == 64);
+  DEBUGASSERT(size == (size_t)lmrespoff);
+
+  /* We append the binary hashes */
+  if(size < (NTLM_BUFSIZE - 0x18)) {
+    memcpy(&ntlmbuf[size], lmresp, 0x18);
+    size += 0x18;
+  }
+
+  DEBUG_OUT({
+    fprintf(stderr, "**** TYPE3 header lmresp=");
+    ntlm_print_hex(stderr, (char *)&ntlmbuf[lmrespoff], 0x18);
+  });
+
+#if USE_NTRESPONSES
+  if(size < (NTLM_BUFSIZE - 0x18)) {
+    DEBUGASSERT(size == (size_t)ntrespoff);
+    memcpy(&ntlmbuf[size], ntresp, 0x18);
+    size += 0x18;
+  }
+
+  DEBUG_OUT({
+    fprintf(stderr, "\n   ntresp=");
+    ntlm_print_hex(stderr, (char *)&ntlmbuf[ntrespoff], 0x18);
+  });
+
+#endif
+
+  DEBUG_OUT({
+    fprintf(stderr, "\n   flags=0x%02.2x%02.2x%02.2x%02.2x 0x%08.8x ",
+            LONGQUARTET(ntlm->flags), ntlm->flags);
+    ntlm_print_flags(stderr, ntlm->flags);
+    fprintf(stderr, "\n****\n");
+  });
+
+  /* Make sure that the domain, user and host strings fit in the
+     buffer before we copy them there. */
+  if(size + userlen + domlen + hostlen >= NTLM_BUFSIZE) {
+    failf(data, "user + domain + host name too big");
+    return CURLE_OUT_OF_MEMORY;
+  }
+
+  DEBUGASSERT(size == domoff);
+  if(unicode)
+    unicodecpy(&ntlmbuf[size], domain, domlen / 2);
+  else
+    memcpy(&ntlmbuf[size], domain, domlen);
+
+  size += domlen;
+
+  DEBUGASSERT(size == useroff);
+  if(unicode)
+    unicodecpy(&ntlmbuf[size], user, userlen / 2);
+  else
+    memcpy(&ntlmbuf[size], user, userlen);
+
+  size += userlen;
+
+  DEBUGASSERT(size == hostoff);
+  if(unicode)
+    unicodecpy(&ntlmbuf[size], host, hostlen / 2);
+  else
+    memcpy(&ntlmbuf[size], host, hostlen);
+
+  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)
+    return CURLE_CONV_FAILED;
+
+#endif
+
+  /* Return with binary blob encoded into base64 */
+  return Curl_base64_encode(NULL, (char *)ntlmbuf, size, outptr, &base64_sz);
+}
+
+#endif /* USE_NTLM */
diff --git a/lib/curl_ntlm_msgs.h b/lib/curl_ntlm_msgs.h
new file mode 100644 (file)
index 0000000..3e037b1
--- /dev/null
@@ -0,0 +1,164 @@
+#ifndef HEADER_CURL_NTLM_MSGS_H
+#define HEADER_CURL_NTLM_MSGS_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, 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.
+ *
+ ***************************************************************************/
+
+#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);
+
+/* 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);
+
+/* 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 clean up the ntlm data structure */
+#ifdef USE_WINDOWS_SSPI
+void Curl_ntlm_sspi_cleanup(struct ntlmdata *ntlm);
+#endif
+
+/* NTLM buffer fixed size, large enough for long user + host + domain */
+#define NTLM_BUFSIZE 1024
+
+/* Stuff only required for curl_ntlm_msgs.c */
+#ifdef BUILDING_CURL_NTLM_MSGS_C
+
+/* Flag bits definitions based on http://davenport.sourceforge.net/ntlm.html */
+
+#define NTLMFLAG_NEGOTIATE_UNICODE               (1<<0)
+/* Indicates that Unicode strings are supported for use in security buffer
+   data. */
+
+#define NTLMFLAG_NEGOTIATE_OEM                   (1<<1)
+/* Indicates that OEM strings are supported for use in security buffer data. */
+
+#define NTLMFLAG_REQUEST_TARGET                  (1<<2)
+/* Requests that the server's authentication realm be included in the Type 2
+   message. */
+
+/* unknown (1<<3) */
+#define NTLMFLAG_NEGOTIATE_SIGN                  (1<<4)
+/* Specifies that authenticated communication between the client and server
+   should carry a digital signature (message integrity). */
+
+#define NTLMFLAG_NEGOTIATE_SEAL                  (1<<5)
+/* Specifies that authenticated communication between the client and server
+   should be encrypted (message confidentiality). */
+
+#define NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE        (1<<6)
+/* Indicates that datagram authentication is being used. */
+
+#define NTLMFLAG_NEGOTIATE_LM_KEY                (1<<7)
+/* Indicates that the LAN Manager session key should be used for signing and
+   sealing authenticated communications. */
+
+#define NTLMFLAG_NEGOTIATE_NETWARE               (1<<8)
+/* unknown purpose */
+
+#define NTLMFLAG_NEGOTIATE_NTLM_KEY              (1<<9)
+/* Indicates that NTLM authentication is being used. */
+
+/* unknown (1<<10) */
+
+#define NTLMFLAG_NEGOTIATE_ANONYMOUS             (1<<11)
+/* Sent by the client in the Type 3 message to indicate that an anonymous
+   context has been established. This also affects the response fields. */
+
+#define NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED       (1<<12)
+/* Sent by the client in the Type 1 message to indicate that a desired
+   authentication realm is included in the message. */
+
+#define NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED  (1<<13)
+/* Sent by the client in the Type 1 message to indicate that the client
+   workstation's name is included in the message. */
+
+#define NTLMFLAG_NEGOTIATE_LOCAL_CALL            (1<<14)
+/* Sent by the server to indicate that the server and client are on the same
+   machine. Implies that the client may use a pre-established local security
+   context rather than responding to the challenge. */
+
+#define NTLMFLAG_NEGOTIATE_ALWAYS_SIGN           (1<<15)
+/* Indicates that authenticated communication between the client and server
+   should be signed with a "dummy" signature. */
+
+#define NTLMFLAG_TARGET_TYPE_DOMAIN              (1<<16)
+/* Sent by the server in the Type 2 message to indicate that the target
+   authentication realm is a domain. */
+
+#define NTLMFLAG_TARGET_TYPE_SERVER              (1<<17)
+/* Sent by the server in the Type 2 message to indicate that the target
+   authentication realm is a server. */
+
+#define NTLMFLAG_TARGET_TYPE_SHARE               (1<<18)
+/* Sent by the server in the Type 2 message to indicate that the target
+   authentication realm is a share. Presumably, this is for share-level
+   authentication. Usage is unclear. */
+
+#define NTLMFLAG_NEGOTIATE_NTLM2_KEY             (1<<19)
+/* Indicates that the NTLM2 signing and sealing scheme should be used for
+   protecting authenticated communications. */
+
+#define NTLMFLAG_REQUEST_INIT_RESPONSE           (1<<20)
+/* unknown purpose */
+
+#define NTLMFLAG_REQUEST_ACCEPT_RESPONSE         (1<<21)
+/* unknown purpose */
+
+#define NTLMFLAG_REQUEST_NONNT_SESSION_KEY       (1<<22)
+/* unknown purpose */
+
+#define NTLMFLAG_NEGOTIATE_TARGET_INFO           (1<<23)
+/* Sent by the server in the Type 2 message to indicate that it is including a
+   Target Information block in the message. */
+
+/* unknown (1<24) */
+/* unknown (1<25) */
+/* unknown (1<26) */
+/* unknown (1<27) */
+/* unknown (1<28) */
+
+#define NTLMFLAG_NEGOTIATE_128                   (1<<29)
+/* Indicates that 128-bit encryption is supported. */
+
+#define NTLMFLAG_NEGOTIATE_KEY_EXCHANGE          (1<<30)
+/* Indicates that the client will provide an encrypted master key in
+   the "Session Key" field of the Type 3 message. */
+
+#define NTLMFLAG_NEGOTIATE_56                    (1<<31)
+/* Indicates that 56-bit encryption is supported. */
+
+#endif /* BUILDING_CURL_NTLM_MSGS_C */
+
+#endif /* USE_NTLM */
+
+#endif /* HEADER_CURL_NTLM_MSGS_H */
index 34877ea73834c0a3b493b058312429d30e8f1231..a183211725b3c8aed4c183f9bd5a2be533e2e305 100644 (file)
@@ -63,7 +63,7 @@
 #include "easyif.h"
 #include "select.h"
 #include "sendf.h" /* for failf function prototype */
-#include "http_ntlm.h"
+#include "curl_ntlm.h"
 #include "connect.h" /* for Curl_getconnectinfo */
 #include "slist.h"
 #include "curl_rand.h"
index 36062d7c20cc4912376bd90a36472bbe2c1c7a58..ef3953ec0e445ae56a5d4dc01172fa96b155aa4b 100644 (file)
@@ -62,7 +62,7 @@
 #include "strequal.h"
 #include "sslgen.h"
 #include "http_digest.h"
-#include "http_ntlm.h"
+#include "curl_ntlm.h"
 #include "curl_ntlm_wb.h"
 #include "http_negotiate.h"
 #include "url.h"
diff --git a/lib/http_ntlm.c b/lib/http_ntlm.c
deleted file mode 100644 (file)
index f7defe0..0000000
+++ /dev/null
@@ -1,253 +0,0 @@
-/***************************************************************************
- *                                  _   _ ____  _
- *  Project                     ___| | | |  _ \| |
- *                             / __| | | | |_) | |
- *                            | (__| |_| |  _ <| |___
- *                             \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, 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 "setup.h"
-
-/* NTLM details:
-
-   http://davenport.sourceforge.net/ntlm.html
-   http://www.innovation.ch/java/ntlm.html
-*/
-
-#ifdef USE_NTLM
-
-#define DEBUG_ME 0
-
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#ifdef HAVE_SYS_WAIT_H
-#include <sys/wait.h>
-#endif
-#ifdef HAVE_SIGNAL_H
-#include <signal.h>
-#endif
-
-#if (defined(NETWARE) && !defined(__NOVELL_LIBC__))
-#include <netdb.h>
-#endif
-
-#include "urldata.h"
-#include "non-ascii.h"  /* for Curl_convert_... prototypes */
-#include "sendf.h"
-#include "select.h"
-#include "rawstr.h"
-#include "curl_base64.h"
-#include "http_ntlm.h"
-#include "curl_ntlm.h"
-#include "curl_ntlm_wb.h"
-#include "url.h"
-#include "strerror.h"
-#include "curl_gethostname.h"
-#include "curl_memory.h"
-
-#define _MPRINTF_REPLACE /* use our functions only */
-#include <curl/mprintf.h>
-
-#if defined(USE_NSS)
-#include "nssg.h"
-#elif defined(USE_WINDOWS_SSPI)
-#include "curl_sspi.h"
-#endif
-
-/* The last #include file should be: */
-#include "memdebug.h"
-
-#if DEBUG_ME
-# define DEBUG_OUT(x) x
-#else
-# define DEBUG_OUT(x)
-#endif
-
-CURLcode Curl_input_ntlm(struct connectdata *conn,
-                         bool proxy,         /* if proxy or not */
-                         const char *header) /* rest of the www-authenticate:
-                                                header */
-{
-  /* point to the correct struct with this */
-  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;
-
-  /* skip initial whitespaces */
-  while(*header && ISSPACE(*header))
-    header++;
-
-  if(checkprefix("NTLM", header)) {
-    header += strlen("NTLM");
-
-    while(*header && ISSPACE(*header))
-      header++;
-
-    if(*header) {
-      result = Curl_ntlm_decode_type2_message(conn->data, header, ntlm);
-      if(CURLE_OK != result)
-        return result;
-
-      ntlm->state = NTLMSTATE_TYPE2; /* We got a type-2 message */
-    }
-    else {
-      if(ntlm->state >= NTLMSTATE_TYPE1) {
-        infof(conn->data, "NTLM handshake failure (internal error)\n");
-        return CURLE_REMOTE_ACCESS_DENIED;
-      }
-
-      ntlm->state = NTLMSTATE_TYPE1; /* We should send away a type-1 */
-    }
-  }
-
-  return result;
-}
-
-/*
- * This is for creating ntlm header output
- */
-CURLcode Curl_output_ntlm(struct connectdata *conn,
-                          bool proxy)
-{
-  char *base64 = NULL;
-  CURLcode error;
-
-  /* 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;
-
-  /* point to the name and password for this */
-  const char *userp;
-  const char *passwdp;
-
-  /* point to the correct struct with this */
-  struct ntlmdata *ntlm;
-  struct auth *authp;
-
-  DEBUGASSERT(conn);
-  DEBUGASSERT(conn->data);
-
-#ifdef USE_NSS
-  if(CURLE_OK != Curl_nss_force_init(conn->data))
-    return CURLE_OUT_OF_MEMORY;
-#endif
-
-  if(proxy) {
-    allocuserpwd = &conn->allocptr.proxyuserpwd;
-    userp = conn->proxyuser;
-    passwdp = conn->proxypasswd;
-    ntlm = &conn->proxyntlm;
-    authp = &conn->data->state.authproxy;
-  }
-  else {
-    allocuserpwd = &conn->allocptr.userpwd;
-    userp = conn->user;
-    passwdp = conn->passwd;
-    ntlm = &conn->ntlm;
-    authp = &conn->data->state.authhost;
-  }
-  authp->done = FALSE;
-
-  /* not set means empty */
-  if(!userp)
-    userp = "";
-
-  if(!passwdp)
-    passwdp = "";
-
-#ifdef USE_WINDOWS_SSPI
-  if(s_hSecDll == NULL) {
-    /* not thread safe and leaks - use curl_global_init() to avoid */
-    CURLcode err = Curl_sspi_global_init();
-    if(s_hSecDll == NULL)
-      return err;
-  }
-#endif
-
-  switch(ntlm->state) {
-  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);
-    if(error)
-      return error;
-
-    if(base64) {
-      Curl_safefree(*allocuserpwd);
-      *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
-                              proxy ? "Proxy-" : "",
-                              base64);
-      DEBUG_OUT(fprintf(stderr, "**** Header %s\n ", *allocuserpwd));
-      free(base64);
-    }
-    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);
-    if(error)
-      return error;
-
-    if(base64) {
-      Curl_safefree(*allocuserpwd);
-      *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
-                              proxy ? "Proxy-" : "",
-                              base64);
-      DEBUG_OUT(fprintf(stderr, "**** %s\n ", *allocuserpwd));
-      free(base64);
-
-      ntlm->state = NTLMSTATE_TYPE3; /* we send a type-3 */
-      authp->done = TRUE;
-    }
-    break;
-
-  case NTLMSTATE_TYPE3:
-    /* connection is already authenticated,
-     * don't send a header in future requests */
-    if(*allocuserpwd) {
-      free(*allocuserpwd);
-      *allocuserpwd = NULL;
-    }
-    authp->done = TRUE;
-    break;
-  }
-
-  return CURLE_OK;
-}
-
-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
-}
-
-#endif /* USE_NTLM */
diff --git a/lib/http_ntlm.h b/lib/http_ntlm.h
deleted file mode 100644 (file)
index a074380..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-#ifndef HEADER_CURL_HTTP_NTLM_H
-#define HEADER_CURL_HTTP_NTLM_H
-/***************************************************************************
- *                                  _   _ ____  _
- *  Project                     ___| | | |  _ \| |
- *                             / __| | | | |_) | |
- *                            | (__| |_| |  _ <| |___
- *                             \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, 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.
- *
- ***************************************************************************/
-
-#ifdef USE_NTLM
-
-/* this is for ntlm header input */
-CURLcode Curl_input_ntlm(struct connectdata *conn, bool proxy,
-                         const char *header);
-
-/* this is for creating ntlm header output */
-CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy);
-
-void Curl_http_ntlm_cleanup(struct connectdata *conn);
-
-#else
-
-#define Curl_http_ntlm_cleanup(a)
-
-#endif
-
-#endif /* HEADER_CURL_HTTP_NTLM_H */
index f1896b013ab69541691792f1d266e20a8041af32..2f4b69cf81dac1d4800ea43f0e66382c00df8a5d 100644 (file)
@@ -78,7 +78,7 @@
 #include "getinfo.h"
 #include "sslgen.h"
 #include "http_digest.h"
-#include "http_ntlm.h"
+#include "curl_ntlm.h"
 #include "http_negotiate.h"
 #include "share.h"
 #include "curl_memory.h"
index 9834e04f8ad56f229d5677680a107e8046fcf4fa..4d39f2e01d81b939271747d89c9028a89fd857c8 100644 (file)
--- a/lib/url.c
+++ b/lib/url.c
@@ -119,7 +119,7 @@ int curl_win32_idn_to_ascii(const char *in, char **out);
 #include "url.h"
 #include "connect.h"
 #include "inet_ntop.h"
-#include "http_ntlm.h"
+#include "curl_ntlm.h"
 #include "socks.h"
 #include "curl_rtmp.h"
 #include "gopher.h"
index 8092cefaa321839cd664f9b6ff655bfc5373af6c..5cab131b089fe00d9164fe6e06ce7f4ee14ce198 100644 (file)
@@ -28,7 +28,7 @@ SOURCE \
   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 curl_rand.c     \
-  http_negotiate.c http_ntlm.c inet_pton.c strtoofft.c strerror.c      \
+  http_negotiate.c curl_ntlm_msgs.c inet_pton.c strtoofft.c strerror.c \
   hostasyn.c hostip4.c hostip6.c hostsyn.c inet_ntop.c parsedate.c     \
   select.c gtls.c sslgen.c tftp.c splay.c strdup.c socks.c ssh.c nss.c \
   qssl.c rawstr.c curl_addrinfo.c socks_gssapi.c socks_sspi.c          \