summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Stenberg <daniel@haxx.se>2003-06-11 13:38:55 +0000
committerDaniel Stenberg <daniel@haxx.se>2003-06-11 13:38:55 +0000
commit73c5f24fa40460f41d6cd9114827383edc57e287 (patch)
treeb006a03480c0aa21c51ae5f0682c7c538b9631c5
parent4c80e103a055b719de04818615349be2b28b7858 (diff)
downloadcurl-73c5f24fa40460f41d6cd9114827383edc57e287.tar.gz
Initial take at NTLM authentication. It doesn't really work at this point
but the infrastructure is there.
-rw-r--r--lib/Makefile.am3
-rw-r--r--lib/base64.c6
-rw-r--r--lib/http.c8
-rw-r--r--lib/http_ntlm.c501
-rw-r--r--lib/http_ntlm.h67
-rw-r--r--lib/transfer.c12
-rw-r--r--lib/url.c15
-rw-r--r--lib/urldata.h18
8 files changed, 626 insertions, 4 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 64cfaa74f..ebec015d8 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -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
diff --git a/lib/base64.c b/lib/base64.c
index 0f461eabd..ee533189f 100644
--- a/lib/base64.c
+++ b/lib/base64.c
@@ -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;
diff --git a/lib/http.c b/lib/http.c
index e5d2b49d3..b06de06a8 100644
--- a/lib/http.c
+++ b/lib/http.c
@@ -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
index 000000000..841342526
--- /dev/null
+++ b/lib/http_ntlm.c
@@ -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
index 000000000..30e0b67a1
--- /dev/null
+++ b/lib/http_ntlm.h
@@ -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
diff --git a/lib/transfer.c b/lib/transfer.c
index 2eda08889..7d060c689 100644
--- a/lib/transfer.c
+++ b/lib/transfer.c
@@ -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
diff --git a/lib/url.c b/lib/url.c
index c328e5ac4..f02eec0cc 100644
--- 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 */
diff --git a/lib/urldata.h b/lib/urldata.h
index 459c5c468..4a2e97f06 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -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: */