1
0
mirror of https://github.com/moparisthebest/curl synced 2024-08-13 17:03:50 -04:00

Many fixes, most of them based on comments by Eric Glass

This commit is contained in:
Daniel Stenberg 2003-06-26 11:26:26 +00:00
parent 445684c409
commit 3b2b2496d7

View File

@ -22,7 +22,12 @@
***************************************************************************/ ***************************************************************************/
#include "setup.h" #include "setup.h"
/* All NTLM details here: http://www.innovation.ch/java/ntlm.html */ /* NTLM details:
http://davenport.sourceforge.net/ntlm.html
http://www.innovation.ch/java/ntlm.html
*/
#ifndef CURL_DISABLE_HTTP #ifndef CURL_DISABLE_HTTP
#ifdef USE_SSLEAY #ifdef USE_SSLEAY
@ -65,23 +70,23 @@
#endif #endif
/* The last #include file should be: */ /* The last #include file should be: */
#ifdef MALLOCDEBUG #ifdef CURLDEBUG
#include "memdebug.h" #include "memdebug.h"
#endif #endif
/* Define this to make the type-3 message include the NT response message */
#undef USE_NTRESPONSES
/* /*
The one and only master resource for NTLM "hacking": (*) = A "security buffer" is a triplet consisting of two shorts and one
long:
====> http://www.innovation.ch/java/ntlm.html <==== 1. a 'short' containing the length of the buffer in bytes
2. a 'short' containing the allocated space for the buffer in bytes
Brought to the world by Ronald Tschalär. 3. a 'long' containing the offset to the start of the buffer from the
beginning of the NTLM message, in bytes.
*/ */
/* Test example header:
WWW-Authenticate: NTLM
*/
CURLntlm Curl_input_ntlm(struct connectdata *conn, CURLntlm Curl_input_ntlm(struct connectdata *conn,
char *header) /* rest of the www-authenticate: char *header) /* rest of the www-authenticate:
@ -101,31 +106,18 @@ CURLntlm Curl_input_ntlm(struct connectdata *conn,
header++; header++;
if(*header) { if(*header) {
/* we got a type-2 message here */ /* We got a type-2 message here:
/* My test-IE session reveived this type-2:
TlRMTVNTUAACAAAAAgACADAAAAAGgoEAc51AYVDgyNcAAAAAAAAAAG4AbgA\
yAAAAQ0MCAAQAQwBDAAEAEgBFAEwASQBTAEEAQgBFAFQASAAEABgAYwBjAC4\
AaQBjAGUAZABlAHYALgBuAHUAAwAsAGUAbABpAHMAYQBiAGUAdABoAC4AYwB\
jAC4AaQBjAGUAZABlAHYALgBuAHUAAAAAAA==
which translates to this:
0x00: 4e 54 4c 4d 53 53 50 00 02 00 00 00 02 00 02 00 | NTLMSSP.........
0x10: 30 00 00 00 06 82 81 00 73 9d 40 61 50 e0 c8 d7 | 0.......s.@aP...
0x20: 00 00 00 00 00 00 00 00 6e 00 6e 00 32 00 00 00 | ........n.n.2...
0x30: 43 43 02 00 04 00 43 00 43 00 01 00 12 00 45 00 | CC....C.C.....E.
0x40: 4c 00 49 00 53 00 41 00 42 00 45 00 54 00 48 00 | L.I.S.A.B.E.T.H.
0x50: 04 00 18 00 63 00 63 00 2e 00 69 00 63 00 65 00 | ....c.c...i.c.e.
0x60: 64 00 65 00 76 00 2e 00 6e 00 75 00 03 00 2c 00 | d.e.v...n.u...,.
0x70: 65 00 6c 00 69 00 73 00 61 00 62 00 65 00 74 00 | e.l.i.s.a.b.e.t.
0x80: 68 00 2e 00 63 00 63 00 2e 00 69 00 63 00 65 00 | h...c.c...i.c.e.
0x90: 64 00 65 00 76 00 2e 00 6e 00 75 00 00 00 00 00 | d.e.v...n.u.....
This is not the same format as described on the web page, but doing repeated
requests show that 0x18-0x1f seems to be the nonce anyway.
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 (optional) 8 bytes (two consecutive longs)
(40) Target Information (optional) security buffer(*)
32 (48) start of data block
*/ */
int size = Curl_base64_decode(header, buffer); int size = Curl_base64_decode(header, buffer);
@ -135,6 +127,9 @@ requests show that 0x18-0x1f seems to be the nonce anyway.
if(size >= 48) if(size >= 48)
/* the nonce of interest is index [24 .. 31], 8 bytes */ /* the nonce of interest is index [24 .. 31], 8 bytes */
memcpy(data->state.ntlm.nonce, &buffer[24], 8); memcpy(data->state.ntlm.nonce, &buffer[24], 8);
/* at index decimal 20, there's a 32bit NTLM flag field */
} }
else { else {
if(data->state.ntlm.state >= NTLMSTATE_TYPE1) if(data->state.ntlm.state >= NTLMSTATE_TYPE1)
@ -198,12 +193,16 @@ static void calc_resp(unsigned char *keys,
*/ */
static void mkhash(char *password, static void mkhash(char *password,
unsigned char *nonce, /* 8 bytes */ unsigned char *nonce, /* 8 bytes */
unsigned char *lmresp, /* must fit 0x18 bytes */ unsigned char *lmresp /* must fit 0x18 bytes */
unsigned char *ntresp) /* must fit 0x18 bytes */ #ifdef USE_NTRESPONSES
, unsigned char *ntresp /* must fit 0x18 bytes */
#endif
)
{ {
unsigned char lmbuffer[21]; unsigned char lmbuffer[21];
#ifdef USE_NTRESPONSES
unsigned char ntbuffer[21]; unsigned char ntbuffer[21];
#endif
unsigned char *pw; unsigned char *pw;
static const unsigned char magic[] = { static const unsigned char magic[] = {
0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25
@ -239,7 +238,10 @@ static void mkhash(char *password,
memset(lmbuffer+16, 0, 5); memset(lmbuffer+16, 0, 5);
} }
/* create LM responses */
calc_resp(lmbuffer, nonce, lmresp);
#ifdef USE_NTRESPONSES
{ {
/* create NT hashed password */ /* create NT hashed password */
MD4_CTX MD4; MD4_CTX MD4;
@ -258,35 +260,22 @@ static void mkhash(char *password,
memset(ntbuffer+16, 0, 8); memset(ntbuffer+16, 0, 8);
} }
/* create responses */
calc_resp(lmbuffer, nonce, lmresp);
calc_resp(ntbuffer, nonce, ntresp); calc_resp(ntbuffer, nonce, ntresp);
#endif
free(pw); free(pw);
} }
/* 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) #define SHORTPAIR(x) ((x) & 0xff), ((x) >> 8)
#define LONGQUARTET(x) ((x) & 0xff), (((x) >> 8)&0xff), \
(((x) >>16)&0xff), ((x)>>24)
/* this is for creating ntlm header output */ /* this is for creating ntlm header output */
CURLcode Curl_output_ntlm(struct connectdata *conn) CURLcode Curl_output_ntlm(struct connectdata *conn)
{ {
struct SessionHandle *data=conn->data; struct SessionHandle *data=conn->data;
const char *domain="CURL"; const char *domain=""; /* empty */
const char *host="HAXX"; const char *host=""; /* empty */
int domlen=strlen(domain); int domlen=strlen(domain);
int hostlen = strlen(host); int hostlen = strlen(host);
int hostoff; /* host name offset */ int hostoff; /* host name offset */
@ -295,49 +284,46 @@ CURLcode Curl_output_ntlm(struct connectdata *conn)
char *base64=NULL; char *base64=NULL;
unsigned char ntlm[256]; /* enough, unless the host/domain is very long */ unsigned char ntlm[256]; /* enough, unless the host/domain is very long */
if(NTLMSTATE_TYPE1 == data->state.ntlm.state) { switch(data->state.ntlm.state) {
case NTLMSTATE_TYPE1:
default: /* for the weird cases we (re)start here */
hostoff = 32; hostoff = 32;
domoff = hostoff + hostlen; domoff = hostoff + hostlen;
/* IE used this as type-1 maessage: /* Create and send a type-1 message:
Authorization: NTLM \ Index Description Content
TlRMTVNTUAABAAAABoIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAAAAAAAwAAAA\r\n 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
(0x4e544c4d53535000)
This translates into: 8 NTLM Message Type long (0x01000000)
12 Flags long
0x00: 4e 54 4c 4d 53 53 50 00 01 00 00 00 06 82 00 00 | NTLMSSP......... 16 Supplied Domain security buffer(*)
0x10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................ 24 Supplied Workstation security buffer(*)
0x20: 00 00 00 00 30 00 00 00 00 00 00 00 30 00 00 00 | ....0.......0... 32 start of data block
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.
We want to send something like this:
0x00: 4e 54 4c 4d 53 53 50 00 01 00 00 00 03 b2 00 00 | NTLMSSP.........
0x10: 05 00 05 00 2b 00 00 00 0b 00 0b 00 20 00 00 00 | ....+...........
0x20: 4c 49 4c 4c 41 53 59 53 54 45 52 48 45 4d 4d 41 | LILLASYSTERHEMMA
*/ */
snprintf((char *)ntlm, sizeof(ntlm), "NTLMSSP%c" snprintf((char *)ntlm, sizeof(ntlm), "NTLMSSP%c"
"\x01" /* type 1 */ "\x01%c%c%c" /* 32-bit type = 1 */
"%c%c%c" "%c%c%c%c" /* 32-bit NTLM flag field */
"\x03\xb2"
"%c%c"
"%c%c" /* domain length */
"%c%c" /* domain length */ "%c%c" /* domain length */
"%c%c" /* domain allocated space */
"%c%c" /* domain name offset */ "%c%c" /* domain name offset */
"%c%c" /* 2 zeroes */ "%c%c" /* 2 zeroes */
"%c%c" /* host length */ "%c%c" /* host length */
"%c%c" /* host length */ "%c%c" /* host allocated space */
"%c%c" /* host name offset */ "%c%c" /* host name offset */
"%c%c" /* 2 zeroes */ "%c%c" /* 2 zeroes */
"%s" /* host name */ "%s" /* host name */
"%s", /* domain string */ "%s", /* domain string */
0,0,0,0,0,0, 0, /* trailing zero */
0,0,0, /* part of type-1 long */
LONGQUARTET(
NTLMFLAG_NEGOTIATE_OEM| /* 2 */
NTLMFLAG_NEGOTIATE_NTLM_KEY /* 200 */
/* equals 0x0202 */
),
SHORTPAIR(domlen), SHORTPAIR(domlen),
SHORTPAIR(domlen), SHORTPAIR(domlen),
SHORTPAIR(domoff), SHORTPAIR(domoff),
@ -350,11 +336,7 @@ CURLcode Curl_output_ntlm(struct connectdata *conn)
/* initial packet length */ /* initial packet length */
size = 32 + hostlen + domlen; size = 32 + 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 */ /* now keeper of the base64 encoded package size */
size = Curl_base64_encode(ntlm, size, &base64); size = Curl_base64_encode(ntlm, size, &base64);
@ -365,55 +347,43 @@ CURLcode Curl_output_ntlm(struct connectdata *conn)
} }
else else
return CURLE_OUT_OF_MEMORY; /* FIX TODO */ return CURLE_OUT_OF_MEMORY; /* FIX TODO */
}
else {
if(NTLMSTATE_TYPE2 == data->state.ntlm.state) {
/* We received the type-2 already, create a type-3 message */
/* break;
My test-IE session sent this type-3:
TlRMTVNTUAADAAAAGAAYAEoAAAAAAAAAYgAAAAUABQA0AAAABgAGADk\ case NTLMSTATE_TYPE2:
AAAALAAsAPwAAAEhFTU1BZGFuaWVsTElMTEFTWVNURVJPVPJELoebUg\ /* We received the type-2 already, create a type-3 message:
4SvW0ed2QmKu0SjX4qNrI=
Which translates to: Index Description Content
0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
0x00: 4e 54 4c 4d 53 53 50 00 03 00 00 00 18 00 18 00 | NTLMSSP......... (0x4e544c4d53535000)
0x10: 4a 00 00 00 00 00 00 00 62 00 00 00 05 00 05 00 | J.......b....... 8 NTLM Message Type long (0x03000000)
0x20: 34 00 00 00 06 00 06 00 39 00 00 00 0b 00 0b 00 | 4.......9....... 12 LM/LMv2 Response security buffer(*)
0x30: 3f 00 00 00 48 45 4d 4d 41 64 61 6e 69 65 6c 4c | ?...HEMMAdanielL 20 NTLM/NTLMv2 Response security buffer(*)
0x40: 49 4c 4c 41 53 59 53 54 45 52 4f 54 f2 44 2e 87 | ILLASYSTEROT.D.. 28 Domain Name security buffer(*)
0x50: 9b 52 0e 12 bd 6d 1e 77 64 26 2a ed 12 8d 7e 2a | .R...m.wd&*...~* 36 User Name security buffer(*)
0x60: 36 b2 | 6. 44 Workstation Name security buffer(*)
(52) Session Key (optional) security buffer(*)
Note how the domain + username + hostname ARE NOT unicoded in any way. (60) Flags (optional) long
Domain and hostname are uppercase, while username are case sensitive. 52 (64) start of data block
We send something like this:
0x00: 4e 54 4c 4d 53 53 50 00 03 00 00 00 18 00 18 00 | NTLMSSP.........
0x10: 6c 00 00 00 18 00 18 00 84 00 00 00 0a 00 0a 00 | l...............
0x20: 40 00 00 00 0c 00 0c 00 4a 00 00 00 16 00 16 00 | @.......J.......
0x30: 56 00 00 00 00 00 00 00 9c 00 00 00 01 82 00 00 | V...............
0x40: 48 00 45 00 4d 00 4d 00 41 00 64 00 61 00 6e 00 | H.E.M.M.A.d.a.n.
0x50: 69 00 65 00 6c 00 4c 00 49 00 4c 00 4c 00 41 00 | i.e.l.L.I.L.L.A.
0x60: 53 00 59 00 53 00 54 00 45 00 52 00 bc ed 28 c9 | S.Y.S.T.E.R...(.
0x70: 16 c4 1b 16 d7 c9 b4 0e ef ef 02 6d 26 8d c0 ba | ...........m&...
0x80: ac b6 5a c1 26 8d c0 ba ac b6 5a c1 26 8d c0 ba | ..Z.&.....Z.&...
0x90: ac b6 5a c1 26 8d c0 ba ac b6 5a c1 | ..Z.&.....Z.
*/ */
{
int lmrespoff; int lmrespoff;
int ntrespoff; int ntrespoff;
int useroff; int useroff;
unsigned char lmresp[0x18]; /* fixed-size */ unsigned char lmresp[0x18]; /* fixed-size */
#ifdef USE_NTRESPONSES
unsigned char ntresp[0x18]; /* fixed-size */ unsigned char ntresp[0x18]; /* fixed-size */
#endif
int userlen = strlen(data->state.user); int userlen = strlen(data->state.user);
mkhash(data->state.passwd, &data->state.ntlm.nonce[0], lmresp, ntresp); mkhash(data->state.passwd, &data->state.ntlm.nonce[0], lmresp
#ifdef USE_NTRESPONSES
, ntresp
#endif
);
/* these are going unicode */ /* these are going unicode */
domlen *= 2; domlen *= 2;
@ -429,29 +399,29 @@ CURLcode Curl_output_ntlm(struct connectdata *conn)
/* Create the big type-3 message binary blob */ /* Create the big type-3 message binary blob */
size = snprintf((char *)ntlm, sizeof(ntlm), size = snprintf((char *)ntlm, sizeof(ntlm),
"NTLMSSP%c" "NTLMSSP%c"
"\x03" /* type 3 */ "\x03%c%c%c" /* type-3, 32 bits */
"%c%c%c" /* 3 zeroes */
"%c%c%c%c" /* LanManager length twice */ "%c%c%c%c" /* LanManager length + allocated space */
"%c%c" /* LanManager offset */ "%c%c" /* LanManager offset */
"%c%c" /* 2 zeroes */ "%c%c" /* 2 zeroes */
"%c%c%c%c" /* NT-response length twice */ "%c%c" /* NT-response length */
"%c%c" /* NT-response allocated space */
"%c%c" /* NT-response offset */ "%c%c" /* NT-response offset */
"%c%c" /* 2 zeroes */ "%c%c" /* 2 zeroes */
"%c%c" /* domain length */ "%c%c" /* domain length */
"%c%c" /* domain length */ "%c%c" /* domain allocated space */
"%c%c" /* domain name offset */ "%c%c" /* domain name offset */
"%c%c" /* 2 zeroes */ "%c%c" /* 2 zeroes */
"%c%c" /* user length */ "%c%c" /* user length */
"%c%c" /* user length */ "%c%c" /* user allocated space */
"%c%c" /* user offset */ "%c%c" /* user offset */
"%c%c" /* 2 zeroes */ "%c%c" /* 2 zeroes */
"%c%c" /* host length */ "%c%c" /* host length */
"%c%c" /* host length */ "%c%c" /* host allocated space */
"%c%c" /* host offset */ "%c%c" /* host offset */
"%c%c%c%c%c%c" /* 6 zeroes */ "%c%c%c%c%c%c" /* 6 zeroes */
@ -467,16 +437,21 @@ CURLcode Curl_output_ntlm(struct connectdata *conn)
/* LanManager response */ /* LanManager response */
/* NT response */ /* NT response */
, ,
0, 0, /* zero termination */
0,0,0, 0,0,0, /* type-3 long, the 24 upper bits */
SHORTPAIR(0x18), /* LanManager response length, twice */ SHORTPAIR(0x18), /* LanManager response length, twice */
SHORTPAIR(0x18), SHORTPAIR(0x18),
SHORTPAIR(lmrespoff), SHORTPAIR(lmrespoff),
0x0, 0x0, 0x0, 0x0,
#ifdef USE_NTRESPONSES
SHORTPAIR(0x18), /* NT-response length, twice */ SHORTPAIR(0x18), /* NT-response length, twice */
SHORTPAIR(0x18), SHORTPAIR(0x18),
#else
0x0, 0x0,
0x0, 0x0,
#endif
SHORTPAIR(ntrespoff), SHORTPAIR(ntrespoff),
0x0, 0x0, 0x0, 0x0,
@ -503,50 +478,25 @@ CURLcode Curl_output_ntlm(struct connectdata *conn)
size=64; size=64;
ntlm[62]=ntlm[63]=0; ntlm[62]=ntlm[63]=0;
#if 1 memcpy(&ntlm[size], data->state.user, userlen);
ascii_to_unicode(&ntlm[size], (unsigned char *)domain, TRUE);
size += domlen;
ascii_to_unicode(&ntlm[size], (unsigned char *)data->state.user, FALSE);
size += userlen; 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 */ /* we append the binary hashes to the end of the blob */
if(size < ((int)sizeof(ntlm) - 0x18)) { if(size < ((int)sizeof(ntlm) - 0x18)) {
memcpy(&ntlm[size], lmresp, 0x18); memcpy(&ntlm[size], lmresp, 0x18);
size += 0x18; size += 0x18;
} }
#ifdef USE_NTRESPONSES
if(size < ((int)sizeof(ntlm) - 0x18)) { if(size < ((int)sizeof(ntlm) - 0x18)) {
memcpy(&ntlm[size], ntresp, 0x18); memcpy(&ntlm[size], ntresp, 0x18);
size += 0x18; size += 0x18;
} }
#endif
ntlm[56] = size & 0xff; ntlm[56] = size & 0xff;
ntlm[57] = size >> 8; ntlm[57] = size >> 8;
#if 0
#undef CHUNK
#define CHUNK "\x4e\x54\x4c\x4d\x53\x53\x50\x00\x03\x00\x00\x00\x18\x00\x18\x00\x4a\x00\x00\x00\x00\x00\x00\x00\x62\x00\x00\x00\x05\x00\x05\x00\x34\x00\x00\x00\x06\x00\x06\x00\x39\x00\x00\x00\x0b\x00\x0b\x00\x3f\x00\x00\x00\x48\x45\x4d\x4d\x41\x64\x61\x6e\x69\x65\x6c\x4c\x49\x4c\x4c\x41\x53\x59\x53\x54\x45\x52\x4f\x54\xf2\x44\x2e\x87\x9b\x52\x0e\x12\xbd\x6d\x1e\x77\x64\x26\x2a\xed\x12\x8d\x7e\x2a\x36\xb2"
memcpy(ntlm, CHUNK, sizeof(CHUNK)-1);
size = sizeof(CHUNK)-1;
#endif
/* convert the binary blob into base64 */ /* convert the binary blob into base64 */
size = Curl_base64_encode(ntlm, size, &base64); size = Curl_base64_encode(ntlm, size, &base64);
@ -560,15 +510,17 @@ CURLcode Curl_output_ntlm(struct connectdata *conn)
data->state.ntlm.state = NTLMSTATE_TYPE3; /* we sent a type-3 */ data->state.ntlm.state = NTLMSTATE_TYPE3; /* we sent a type-3 */
} else }
if(NTLMSTATE_TYPE3 == data->state.ntlm.state) { break;
case NTLMSTATE_TYPE3:
/* connection is already authenticated, /* connection is already authenticated,
* don't send a header in future requests */ * don't send a header in future requests */
if(conn->allocptr.userpwd) { if(conn->allocptr.userpwd) {
free(conn->allocptr.userpwd); free(conn->allocptr.userpwd);
conn->allocptr.userpwd=NULL; conn->allocptr.userpwd=NULL;
} }
} break;
} }
return CURLE_OK; return CURLE_OK;