]> granicus.if.org Git - curl/commitdiff
Initial take at NTLM authentication. It doesn't really work at this point
authorDaniel Stenberg <daniel@haxx.se>
Wed, 11 Jun 2003 13:38:55 +0000 (13:38 +0000)
committerDaniel Stenberg <daniel@haxx.se>
Wed, 11 Jun 2003 13:38:55 +0000 (13:38 +0000)
but the infrastructure is there.

lib/Makefile.am
lib/base64.c
lib/http.c
lib/http_ntlm.c [new file with mode: 0644]
lib/http_ntlm.h [new file with mode: 0644]
lib/transfer.c
lib/url.c
lib/urldata.h

index 64cfaa74fbb02154fbe79e49e14cdec09d918f84..ebec015d816e2a4459ba25f60f3731a3b4182aad 100644 (file)
@@ -68,7 +68,8 @@ strequal.h easy.c security.h security.c krb4.c krb4.h memdebug.c      \
 memdebug.h inet_ntoa_r.h http_chunks.c http_chunks.h strtok.c strtok.h \
 connect.c connect.h llist.c llist.h hash.c hash.h multi.c              \
 content_encoding.c content_encoding.h share.c share.h http_digest.c \
-md5.c md5.h http_digest.h http_negotiate.c http_negotiate.h
+md5.c md5.h http_digest.h http_negotiate.c http_negotiate.h \
+http_ntlm.c http_ntlm.h
 
 noinst_HEADERS = setup.h transfer.h
 
index 0f461eabd4f5c59e7e25c6d19db6bde8c4ec85a8..ee533189f92defd290a4f36b613c318505e4dd09 100644 (file)
@@ -232,13 +232,17 @@ int main(int argc, char **argv, char **envp)
   int base64Len;
   unsigned char *data;
   int dataLen;
+  int i;
        
   base64 = (char *)suck(&base64Len);
   data = (unsigned char *)malloc(base64Len * 3/4 + 8);
   dataLen = Curl_base64_decode(base64, data);
   
   fprintf(stderr, "%d\n", dataLen);
-  fwrite(data,1,dataLen,stdout);
+
+  for(i=0; i < dataLen; i++) 
+    printf("%02x ", data[i]);
+  puts("");
   
   free(base64); free(data);
   return 0;
index e5d2b49d377391f771bd4060a9e5ac4f3f6cea59..b06de06a87bcee8e412b1b86dba759b45c6e299b 100644 (file)
@@ -90,6 +90,7 @@
 #include "strequal.h"
 #include "ssluse.h"
 #include "http_digest.h"
+#include "http_ntlm.h"
 
 #define _MPRINTF_REPLACE /* use our functions only */
 #include <curl/mprintf.h>
@@ -696,7 +697,12 @@ CURLcode Curl_http(struct connectdata *conn)
        return result;
   } else
 #endif
-  if(data->state.digest.nonce) {
+  if(data->state.ntlm.state) {
+    result = Curl_output_ntlm(conn);
+    if(result)
+      return result;
+  }
+  else if(data->state.digest.nonce) {
     result = Curl_output_digest(conn,
                                 (unsigned char *)request,
                                 (unsigned char *)ppath);
diff --git a/lib/http_ntlm.c b/lib/http_ntlm.c
new file mode 100644 (file)
index 0000000..8413425
--- /dev/null
@@ -0,0 +1,501 @@
+/***************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2003, Daniel Stenberg, <daniel@haxx.se>, 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.
+ *
+ * $Id$
+ ***************************************************************************/
+#include "setup.h"
+
+/* All NTLM details here: http://www.innovation.ch/java/ntlm.html */
+
+#ifndef CURL_DISABLE_HTTP
+#ifdef USE_SSLEAY
+/* We need OpenSSL for the crypto lib to provide us with MD4 and DES */
+
+/* -- WIN32 approved -- */
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include "urldata.h"
+#include "sendf.h"
+#include "strequal.h"
+#include "base64.h"
+#include "http_ntlm.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#include <openssl/des.h>
+#include <openssl/md4.h>
+
+/* The last #include file should be: */
+#ifdef MALLOCDEBUG
+#include "memdebug.h"
+#endif
+
+/*
+  The one and only master resource for NTLM "hacking":
+
+  ====> http://www.innovation.ch/java/ntlm.html <====
+
+  Brought to the world by Ronald Tschalär.
+*/
+
+/* Test example header:
+
+WWW-Authenticate: NTLM
+
+*/
+
+CURLntlm Curl_input_ntlm(struct connectdata *conn,
+                         char *header) /* rest of the www-authenticate:
+                                          header */
+{
+  struct SessionHandle *data=conn->data;
+
+  /* skip initial whitespaces */
+  while(*header && isspace((int)*header))
+    header++;
+
+  if(checkprefix("NTLM", header)) {
+    char buffer[256];
+    header += strlen("NTLM");
+
+    while(*header && isspace((int)*header))
+      header++;
+
+    if(*header) {
+      /* we got a type-2 message here */
+
+      /* My test-IE session reveived this type-2:
+
+      TlRMTVNTUAACAAAAAgACADAAAAAGgoEAc51AYVDgyNcAAAAAAAAAAG4AbgA\
+      yAAAAQ0MCAAQAQwBDAAEAEgBFAEwASQBTAEEAQgBFAFQASAAEABgAYwBjAC4\
+      AaQBjAGUAZABlAHYALgBuAHUAAwAsAGUAbABpAHMAYQBiAGUAdABoAC4AYwB\
+      jAC4AaQBjAGUAZABlAHYALgBuAHUAAAAAAA==
+
+      which translates to this:
+
+      4e 54 4c 4d 53 53 50 00 02 00 00 00 02 00 02 00 30 00 00 00 06 82 81 00
+      73 9d 40 61 50 e0 c8 d7 00 00 00 00 00 00 00 00 6e 00 6e 00 32 00 00 00
+      43 43 02 00 04 00 43 00 43 00 01 00 12 00 45 00 4c 00 49 00 53 00 41 00
+      42 00 45 00 54 00 48 00 04 00 18 00 63 00 63 00 2e 00 69 00 63 00 65 00
+      64 00 65 00 76 00 2e 00 6e 00 75 00 03 00 2c 00 65 00 6c 00 69 00 73 00
+      61 00 62 00 65 00 74 00 68 00 2e 00 63 00 63 00 2e 00 69 00 63 00 65 00
+      64 00 65 00 76 00 2e 00 6e 00 75 00 00 00 00 00
+
+      */
+
+      int size = Curl_base64_decode(header, buffer);
+
+      data->state.ntlm.state = NTLMSTATE_TYPE2; /* we got a type-2 */
+
+      if(size == 48)
+        /* the nonce of interest is index [24 .. 31], 8 bytes */
+        memcpy(data->state.ntlm.nonce, &buffer[24], 8);
+    }
+    else {
+      data->state.ntlm.state = NTLMSTATE_TYPE1; /* we should sent away a
+                                                  type-1 */
+    }
+  }
+  return CURLNTLM_FINE;
+}
+
+/*
+ * Turns a 56 bit key into the 64 bit, odd parity key and sets the key.  The
+ * key schedule ks is also set.
+ */
+static void setup_des_key(unsigned char *key_56,
+                          DES_key_schedule *ks)
+{
+  DES_cblock key;
+
+  key[0] = key_56[0];
+  key[1] = ((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1);
+  key[2] = ((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2);
+  key[3] = ((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3);
+  key[4] = ((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4);
+  key[5] = ((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5);
+  key[6] = ((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6);
+  key[7] =  (key_56[6] << 1) & 0xFF;
+
+  DES_set_odd_parity(&key);
+  DES_set_key(&key, ks);
+}
+
+ /*
+  * takes a 21 byte array and treats it as 3 56-bit DES keys. The
+  * 8 byte plaintext is encrypted with each key and the resulting 24
+  * bytes are stored in the results array.
+  */
+static void calc_resp(unsigned char *keys,
+                      unsigned char *plaintext,
+                      unsigned char *results)
+{
+  des_key_schedule ks;
+
+  setup_des_key(keys, &ks);
+  DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) results, &ks,
+                  DES_ENCRYPT);
+
+  setup_des_key(keys+7, &ks);
+  DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results+8), &ks,
+                  DES_ENCRYPT);
+
+  setup_des_key(keys+14, &ks);
+  DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results+16), &ks,
+                  DES_ENCRYPT);
+}
+
+static void mkhash(char *password,
+                   unsigned char *nonce,  /* 8 bytes */
+                   unsigned char *lmresp, /* must fit 0x18 bytes */
+                   unsigned char *ntresp) /* must fit 0x18 bytes */
+{
+  /* setup LanManager password */
+  unsigned char lmbuffer[0x18];
+  unsigned char ntbuffer[0x18];
+  
+  unsigned char lm_pw[14];
+  int len = strlen(password);
+  unsigned char magic[] = { 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 };
+  int i;
+
+  if (len > 14)
+    len = 14;
+  
+  for (i=0; i<len; i++)
+    lm_pw[i] = toupper(password[i]);
+
+  for (; i<14; i++)
+    lm_pw[i] = 0;
+
+  /* create LanManager hashed password */
+  {
+    DES_key_schedule ks;
+
+    setup_des_key(lm_pw, &ks);
+    DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)lmbuffer, &ks,
+                    DES_ENCRYPT);
+  
+    setup_des_key(lm_pw+7, &ks);
+    DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)lmbuffer+8, &ks,
+                    DES_ENCRYPT);
+
+    memset(lmbuffer+16, 0, 5);
+
+  }
+
+  {
+    /* create NT hashed password */
+    int len = strlen(password);
+    unsigned char nt_pw[256];
+    MD4_CTX MD4;
+
+    for (i=0; i<len; i++) {
+      nt_pw[2*i]   = password[i];
+      nt_pw[2*i+1] = 0;
+    }
+
+    MD4_Init(&MD4);
+    MD4_Update(&MD4, nt_pw, 2*len);
+    MD4_Final(nt_pw, &MD4);
+
+    memset(ntbuffer+16, 0, 5);
+
+  }
+  /* create responses */
+
+  calc_resp(lmbuffer, nonce, lmresp);
+  calc_resp(ntbuffer, nonce, ntresp);
+}
+
+/* convert an ascii string to upper case unicode, the destination buffer
+   must fit twice the source size */
+static void ascii_to_unicode(unsigned char *destunicode,
+                             unsigned char *sourceascii,
+                             bool conv)
+{
+  while (*sourceascii) {
+    destunicode[0] = conv?toupper(*sourceascii):*sourceascii;
+    destunicode[1] = '\0';
+    destunicode += 2;
+    sourceascii++;
+  }
+}
+
+#define SHORTPAIR(x) ((x) & 0xff), ((x) >> 8)
+
+/* this is for creating ntlm header output */
+CURLcode Curl_output_ntlm(struct connectdata *conn)
+{
+  struct SessionHandle *data=conn->data;
+  const char *domain="HEMMA";
+  const char *host="LILLASYSTER";
+  int domlen=strlen(domain);
+  int hostlen = strlen(host);
+  int hostoff; /* host name offset */
+  int domoff;  /* domain name offset */
+  int size;
+  char *base64=NULL;
+
+  unsigned char ntlm[256]; /* enough, unless the host/domain is very long */
+  if(NTLMSTATE_TYPE1 == data->state.ntlm.state) {
+    hostoff = 32;
+    domoff = hostoff + hostlen;
+    
+    /* IE used this in the initial dump:
+
+    Authorization: NTLM \
+    TlRMTVNTUAABAAAABoIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAAAAAAAwAAAA\r\n
+
+    This translates into:
+
+    4e 54 4c 4d 53 53 50 00 01 00 00 00 06 82 00 00 00 00 00 00 00 00 00 00 00
+    00 00 00 00 00 00 00 00 00 00 00 30 00 00 00 00 00 00 00 30 00 00 00
+
+    Which isn't following the web spec. This uses 0x8206 instead of 0xb203
+    and sends a longer chunk of data than we do! Interestingly, there's no
+    host or domain either.
+
+    */
+
+    snprintf((char *)ntlm, sizeof(ntlm), "NTLMSSP%c"
+             "\x01" /* type 1 */
+             "%c%c%c"
+             "\x03\xb2"
+             "%c%c"
+             "%c%c"  /* domain length */
+             "%c%c"  /* domain length */
+             "%c%c"  /* domain name offset */
+             "%c%c"  /* host length */
+             "%c%c"  /* host length */
+             "%c%c"  /* host name offset */
+             "%c%c"
+             "%s" /* host name */
+             "%s", /* domain string */
+             0,0,0,0,0,0,
+             SHORTPAIR(domlen),
+             SHORTPAIR(domlen),
+             SHORTPAIR(domoff),
+             SHORTPAIR(hostlen),
+             SHORTPAIR(hostlen),
+             SHORTPAIR(hostoff),
+             0,0,
+             host, domain);
+
+    /* initial packet length */
+    size = 8 + 1 + 3 + 18 + hostlen + domlen;
+#if 0
+    #define CHUNK "\x4e\x54\x4c\x4d\x53\x53\x50\x00\x01\x00\x00\x00\x06\x82\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x30\x00\x00\x00\x00\x00\x00\x00\x30\x00\x00\x00"
+    memcpy(ntlm, CHUNK, sizeof(CHUNK)-1);
+    size = sizeof(CHUNK)-1;
+#endif    
+    /* now keeper of the base64 encoded package size */
+    size = Curl_base64_encode(ntlm, size, &base64);
+
+    if(size >0 ) {
+      conn->allocptr.userpwd = aprintf("Authorization: NTLM %s\r\n",
+                                       base64);
+      free(base64);
+    }
+    else
+      return CURLE_OUT_OF_MEMORY; /* FIX TODO */
+  }
+  else {
+    /* We are not in the first state, create a type-3 message */
+
+    /*
+      My test-IE session sent this type-3:
+
+      TlRMTVNTUAADAAAAGAAYAEoAAAAAAAAAYgAAAAUABQA0AAAABgAGADk\
+      AAAALAAsAPwAAAEhFTU1BZGFuaWVsTElMTEFTWVNURVJPVPJELoebUg\
+      4SvW0ed2QmKu0SjX4qNrI=
+
+      Which translates to:
+
+      4e 54 4c 4d 53 53 50 00 03 00 00 00 18 00 18 00 4a 00 00 00 00 00 00 00
+      62 00 00 00 05 00 05 00 34 00 00 00 06 00 06 00 39 00 00 00 0b 00 0b 00
+      3f 00 00 00 48 45 4d 4d 41 64 61 6e 69 65 6c 4c 49 4c 4c 41 53 59 53 54
+      45 52 4f 54 f2 44 2e 87 9b 52 0e 12 bd 6d 1e 77 64 26 2a ed 12 8d 7e 2a
+      36 b2
+
+      Note how the domain + username + hostname ARE NOT unicoded in any way.
+      Domain and hostname are uppercase, while username are case sensitive.
+
+      We sent (badly):
+
+      4e 54 4c 4d 53 53 50 00 03 00 00 00 18 00 18 00 56 00 00 00 00 00 00 00
+      6e 00 00 00 05 00 05 00 40 00 00 00 06 00 06 00 45 00 00 00 0b 00 0b 00
+      4b 00 00 00 00 00 00 00 6c 00 00 00 01 82 48 45 4d 4d 41 64 61 6e 69 65
+      6c 4c 49 4c 4c 41 53 59 53 54 45 52 86 99 4a 4f 1a 54 93 85 f9 a4 85 d7
+      ed 14 17 31 8c a6 4d e9 c1 b1 23 a7
+    */
+
+    int lmrespoff;
+    int ntrespoff;
+    int useroff;
+    unsigned char lmresp[0x18+1];
+    unsigned char ntresp[0x18+1];
+
+    int userlen = strlen(data->state.user);
+    
+    mkhash(data->state.passwd, &data->state.ntlm.nonce[0], lmresp, ntresp);
+
+    /* these are going unicode */
+    domlen *= 2;
+    userlen *= 2;
+    hostlen *= 2;
+
+    domoff = 64; /* always */
+    useroff = domoff + domlen;
+    hostoff = useroff + userlen;
+    lmrespoff = hostoff + hostlen;
+    ntrespoff = lmrespoff + 0x18;
+
+    /* Create the big type-3 message binary blob */
+    size = snprintf((char *)ntlm, sizeof(ntlm),
+                    "NTLMSSP%c"
+                    "\x03" /* type 3 */
+                    "%c%c%c" /* 3 zeroes */
+
+                    "%c%c%c%c" /* LanManager length twice */
+                    "%c%c" /* LanManager offset */
+                    "%c%c" /* 2 zeroes */
+
+                    "%c%c%c%c" /* NT-response length twice */
+                    "%c%c" /* NT-response offset */
+                    "%c%c" /* 2 zeroes */
+                    
+                    "%c%c"  /* domain length */
+                    "%c%c"  /* domain length */
+                    "%c%c"  /* domain name offset */
+                    "%c%c"  /* 2 zeroes */
+                    
+                    "%c%c"  /* user length */
+                    "%c%c"  /* user length */
+                    "%c%c"  /* user offset */
+                    "%c%c"  /* 2 zeroes */
+                    
+                    "%c%c"  /* host length */
+                    "%c%c"  /* host length */
+                    "%c%c"  /* host offset */
+                    "%c%c%c%c%c%c"  /* 6 zeroes */
+                    
+                    "\xff\xff"  /* message length */
+                    "%c%c"  /* 2 zeroes */
+                    
+                    "\x01\x82" /* flags */
+                    "%c%c"  /* 2 zeroes */
+
+                    /* domain string */
+                    /* user string */
+                    /* host string */
+                    /* LanManager response */
+                    /* NT response */
+                    ,
+                    0,
+                    0,0,0,
+
+                    SHORTPAIR(0x18),  /* LanManager response length, twice */
+                    SHORTPAIR(0x18),
+                    SHORTPAIR(lmrespoff),
+                    0x0, 0x0,
+                    
+                    SHORTPAIR(0x18),  /* NT-response length, twice */
+                    SHORTPAIR(0x18),
+                    SHORTPAIR(ntrespoff),
+                    0x0, 0x0,
+
+                    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);
+
+    /* size is now 64 */
+#if 1
+    ascii_to_unicode(&ntlm[size], (unsigned char *)domain, TRUE);
+    size += domlen;
+    
+    ascii_to_unicode(&ntlm[size], (unsigned char *)data->state.user, FALSE);
+    size += userlen;
+
+    ascii_to_unicode(&ntlm[size], (unsigned char *)host, TRUE);
+    size += hostlen;
+#else
+    strcpy(&ntlm[size], (unsigned char *)domain);
+    size += domlen;
+
+    strcpy(&ntlm[size], (unsigned char *)data->state.user);
+    size += userlen;
+
+    strcpy(&ntlm[size], (unsigned char *)host);
+    size += hostlen;
+#endif
+
+    /* we append the binary hashes to the end of the blob */
+    if(size < ((int)sizeof(ntlm) - 0x18)) {
+      memcpy(&ntlm[size], lmresp, 0x18);
+      size += 0x18;
+    }
+#ifdef USE_NT
+    if(size < ((int)sizeof(ntlm) - 0x18)) {      
+      memcpy(&ntlm[size+0x18], ntresp, 0x18);
+      size += 0x18*2;
+    }
+#endif
+
+    ntlm[56] = size & 0xff;
+    ntlm[57] = size >> 8;
+    
+    /* convert the binary blob into base64 */
+    size = Curl_base64_encode(ntlm, size, &base64);
+
+    if(size >0 ) {
+      conn->allocptr.userpwd = aprintf("Authorization: NTLM %s\r\n",
+                                       base64);
+      free(base64);
+    }
+    else
+      return CURLE_OUT_OF_MEMORY; /* FIX TODO */
+
+  }
+
+  return CURLE_OK;
+}
+#endif /* USE_SSLEAY */
+#endif /* !CURL_DISABLE_HTTP */
diff --git a/lib/http_ntlm.h b/lib/http_ntlm.h
new file mode 100644 (file)
index 0000000..30e0b67
--- /dev/null
@@ -0,0 +1,67 @@
+#ifndef __HTTP_NTLM_H
+#define __HTTP_NTLM_H
+/***************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2003, Daniel Stenberg, <daniel@haxx.se>, 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.
+ *
+ * $Id$
+ ***************************************************************************/
+
+typedef enum {
+  CURLNTLM_NONE, /* not a ntlm */
+  CURLNTLM_BAD,  /* an ntlm, but one we don't like */
+  CURLNTLM_FIRST, /* the first 401-reply we got with NTLM */
+  CURLNTLM_FINE, /* an ntlm we act on */
+
+  CURLNTLM_LAST  /* last entry in this enum, don't use */
+} CURLntlm;
+
+/* this is for ntlm header input */
+CURLntlm Curl_input_ntlm(struct connectdata *conn, char *header);
+
+/* this is for creating ntlm header output */
+CURLcode Curl_output_ntlm(struct connectdata *conn);
+
+void Curl_ntlm_cleanup(struct SessionHandle *data);
+
+
+/* type-1 octet-stream, sent in the first NTLM-authenticated request
+
+byte    protocol[8];     'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'
+byte    type;            0x01
+byte    zero[3];
+short   flags;           0xb203
+byte    zero[2];
+
+short   dom_len;         domain string length
+short   dom_len;         domain string length
+short   dom_off;         domain string offset
+byte    zero[2];
+
+short   host_len;        host string length
+short   host_len;        host string length
+short   host_off;        host string offset (always 0x20)
+byte    zero[2];
+
+byte    host[*];         host string (ASCII)
+byte    dom[*];          domain string (ASCII)
+
+*/
+
+#endif
index 2eda08889219472b7e7b55588e603b2d371b2fca..7d060c689c1fd5c85db3bb76b7dd49eb19fabbbb 100644 (file)
@@ -96,6 +96,7 @@
 #include "getinfo.h"
 #include "ssluse.h"
 #include "http_digest.h"
+#include "http_ntlm.h"
 #ifdef GSSAPI
 #include "http_negotiate.h"
 #endif
@@ -736,6 +737,17 @@ CURLcode Curl_readwrite(struct connectdata *conn,
                 conn->newurl = strdup(data->change.url);
            }
 #endif
+            else if(Curl_compareheader(k->p,
+                                       "WWW-Authenticate:", "NTLM") &&
+                    (401 == k->httpcode) &&
+                    data->set.httpntlm /* NTLM authentication is 
+                                          activated */) {
+              CURLntlm ntlm;
+              ntlm = Curl_input_ntlm(conn,
+                                     k->p+strlen("WWW-Authenticate:"));
+
+              conn->newurl = strdup(data->change.url); /* clone string */
+            }
             else if(checkprefix("WWW-Authenticate:", k->p) &&
                     (401 == k->httpcode) &&
                     data->set.httpdigest /* Digest authentication is 
index c328e5ac456757bf3a5a2dd5ce413a879f358446..f02eec0cc02aaf7905689240deab267f9f26b6a0 100644 (file)
--- a/lib/url.c
+++ b/lib/url.c
@@ -855,17 +855,32 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...)
       /* default */
       data->set.httpdigest = FALSE;
       data->set.httpnegotiate = FALSE;
+      data->set.httpntlm = FALSE;      
       break;
     case CURLHTTP_DIGEST:
       /* Enable HTTP Digest authentication */
       data->set.httpdigest = TRUE;
       data->set.httpnegotiate = FALSE;
+      data->set.httpntlm = FALSE;      
       break;
+    case CURLHTTP_NTLM:
+      /* Enable HTTP NTLM authentication */
+#ifdef USE_SSLEAY
+      /* We can only support NTLM if OpenSSL is present, as we need their
+         crypto package for it */
+      data->set.httpdigest = FALSE;
+      data->set.httpnegotiate = FALSE;
+      data->set.httpntlm = TRUE;      
+      break;
+#else
+      /* fall-through */
+#endif
     case CURLHTTP_NEGOTIATE:
 #ifdef GSSAPI
       /* Enable HTTP Negotaiate authentication */
       data->set.httpdigest = FALSE;
       data->set.httpnegotiate = TRUE;
+      data->set.httpntlm = FALSE;      
       break;
 #else
       /* fall-through */
index 459c5c46825923023712a22e9482eee33e31d00b..4a2e97f06f67583cde9e321aa3a7fb4ac58d6d98 100644 (file)
@@ -164,6 +164,20 @@ struct digestdata {
   int algo;
 };
 
+typedef enum {
+  NTLMSTATE_NONE,
+  NTLMSTATE_TYPE1,
+  NTLMSTATE_TYPE2,
+  NTLMSTATE_TYPE3,
+  NTLMSTATE_LAST
+} curlntlm;
+
+/* Struct used for Digest challenge-response authentication */
+struct ntlmdata {
+  curlntlm state;
+  unsigned char nonce[8];
+};
+
 #ifdef GSSAPI
 struct negotiatedata {
   OM_uint32 status;
@@ -640,6 +654,7 @@ struct UrlState {
                       is always set TRUE when curl_easy_perform() is called. */
 
   struct digestdata digest;
+  struct ntlmdata ntlm;
 
 #ifdef GSSAPI
   struct negotiatedata negotiate;
@@ -688,8 +703,9 @@ struct UserDefined {
   char *set_proxy;   /* proxy to use */
   long use_port;     /* which port to use (when not using default) */
   char *userpwd;     /* <user:password>, if used */
-  bool httpdigest;   /* if HTTP Digest is enabled */
+  bool httpdigest;    /* if HTTP Digest authentication is enabled */
   bool httpnegotiate; /* if HTTP Negotiate authentication is enabled */
+  bool httpntlm;      /* if HTTP NTLM authentication is enabled */
   char *set_range;   /* range, if used. See README for detailed specification
                         on this syntax. */
   long followlocation; /* as in HTTP Location: */