Loading lib/http_ntlm.c +131 −179 Original line number Diff line number Diff line Loading @@ -22,7 +22,12 @@ ***************************************************************************/ #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 #ifdef USE_SSLEAY Loading Loading @@ -65,23 +70,23 @@ #endif /* The last #include file should be: */ #ifdef MALLOCDEBUG #ifdef CURLDEBUG #include "memdebug.h" #endif /* The one and only master resource for NTLM "hacking": /* Define this to make the type-3 message include the NT response message */ #undef USE_NTRESPONSES ====> http://www.innovation.ch/java/ntlm.html <==== /* (*) = A "security buffer" is a triplet consisting of two shorts and one long: Brought to the world by Ronald Tschalr. 1. a 'short' containing the length of the buffer 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 from the beginning of the NTLM message, in bytes. */ /* Test example header: WWW-Authenticate: NTLM */ CURLntlm Curl_input_ntlm(struct connectdata *conn, char *header) /* rest of the www-authenticate: Loading @@ -101,31 +106,18 @@ CURLntlm Curl_input_ntlm(struct connectdata *conn, 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: 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. /* We got a type-2 message here: 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); Loading @@ -135,6 +127,9 @@ requests show that 0x18-0x1f seems to be the nonce anyway. if(size >= 48) /* the nonce of interest is index [24 .. 31], 8 bytes */ memcpy(data->state.ntlm.nonce, &buffer[24], 8); /* at index decimal 20, there's a 32bit NTLM flag field */ } else { if(data->state.ntlm.state >= NTLMSTATE_TYPE1) Loading Loading @@ -198,12 +193,16 @@ static void calc_resp(unsigned char *keys, */ static void mkhash(char *password, unsigned char *nonce, /* 8 bytes */ unsigned char *lmresp, /* must fit 0x18 bytes */ unsigned char *ntresp) /* must fit 0x18 bytes */ unsigned char *lmresp /* must fit 0x18 bytes */ #ifdef USE_NTRESPONSES , unsigned char *ntresp /* must fit 0x18 bytes */ #endif ) { unsigned char lmbuffer[21]; #ifdef USE_NTRESPONSES unsigned char ntbuffer[21]; #endif unsigned char *pw; static const unsigned char magic[] = { 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 Loading Loading @@ -239,7 +238,10 @@ static void mkhash(char *password, memset(lmbuffer+16, 0, 5); } /* create LM responses */ calc_resp(lmbuffer, nonce, lmresp); #ifdef USE_NTRESPONSES { /* create NT hashed password */ MD4_CTX MD4; Loading @@ -258,35 +260,22 @@ static void mkhash(char *password, memset(ntbuffer+16, 0, 8); } /* create responses */ calc_resp(lmbuffer, nonce, lmresp); calc_resp(ntbuffer, nonce, ntresp); #endif 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 LONGQUARTET(x) ((x) & 0xff), (((x) >> 8)&0xff), \ (((x) >>16)&0xff), ((x)>>24) /* this is for creating ntlm header output */ CURLcode Curl_output_ntlm(struct connectdata *conn) { struct SessionHandle *data=conn->data; const char *domain="CURL"; const char *host="HAXX"; const char *domain=""; /* empty */ const char *host=""; /* empty */ int domlen=strlen(domain); int hostlen = strlen(host); int hostoff; /* host name offset */ Loading @@ -295,49 +284,46 @@ CURLcode Curl_output_ntlm(struct connectdata *conn) char *base64=NULL; 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; domoff = hostoff + hostlen; /* IE used this as type-1 maessage: /* Create and send a type-1 message: Authorization: NTLM \ TlRMTVNTUAABAAAABoIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAAAAAAAwAAAA\r\n This translates into: 0x00: 4e 54 4c 4d 53 53 50 00 01 00 00 00 06 82 00 00 | NTLMSSP......... 0x10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................ 0x20: 00 00 00 00 30 00 00 00 00 00 00 00 30 00 00 00 | ....0.......0... 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 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 start of data block */ snprintf((char *)ntlm, sizeof(ntlm), "NTLMSSP%c" "\x01" /* type 1 */ "%c%c%c" "\x03\xb2" "%c%c" "%c%c" /* domain length */ "\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 length */ "%c%c" /* host allocated space */ "%c%c" /* host name offset */ "%c%c" /* 2 zeroes */ "%s" /* host name */ "%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(domoff), Loading @@ -350,11 +336,7 @@ CURLcode Curl_output_ntlm(struct connectdata *conn) /* initial packet length */ 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 */ size = Curl_base64_encode(ntlm, size, &base64); Loading @@ -365,55 +347,43 @@ CURLcode Curl_output_ntlm(struct connectdata *conn) } else 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 */ /* My test-IE session sent this type-3: TlRMTVNTUAADAAAAGAAYAEoAAAAAAAAAYgAAAAUABQA0AAAABgAGADk\ AAAALAAsAPwAAAEhFTU1BZGFuaWVsTElMTEFTWVNURVJPVPJELoebUg\ 4SvW0ed2QmKu0SjX4qNrI= Which translates to: 0x00: 4e 54 4c 4d 53 53 50 00 03 00 00 00 18 00 18 00 | NTLMSSP......... 0x10: 4a 00 00 00 00 00 00 00 62 00 00 00 05 00 05 00 | J.......b....... 0x20: 34 00 00 00 06 00 06 00 39 00 00 00 0b 00 0b 00 | 4.......9....... 0x30: 3f 00 00 00 48 45 4d 4d 41 64 61 6e 69 65 6c 4c | ?...HEMMAdanielL 0x40: 49 4c 4c 41 53 59 53 54 45 52 4f 54 f2 44 2e 87 | ILLASYSTEROT.D.. 0x50: 9b 52 0e 12 bd 6d 1e 77 64 26 2a ed 12 8d 7e 2a | .R...m.wd&*...~* 0x60: 36 b2 | 6. Note how the domain + username + hostname ARE NOT unicoded in any way. Domain and hostname are uppercase, while username are case sensitive. 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. break; case NTLMSTATE_TYPE2: /* We received the type-2 already, create a type-3 message: 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 Domain Name security buffer(*) 36 User Name security buffer(*) 44 Workstation Name security buffer(*) (52) Session Key (optional) security buffer(*) (60) Flags (optional) long 52 (64) start of data block */ { int lmrespoff; int ntrespoff; int useroff; unsigned char lmresp[0x18]; /* fixed-size */ #ifdef USE_NTRESPONSES unsigned char ntresp[0x18]; /* fixed-size */ #endif 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 */ domlen *= 2; Loading @@ -429,29 +399,29 @@ CURLcode Curl_output_ntlm(struct connectdata *conn) /* Create the big type-3 message binary blob */ size = snprintf((char *)ntlm, sizeof(ntlm), "NTLMSSP%c" "\x03" /* type 3 */ "%c%c%c" /* 3 zeroes */ "\x03%c%c%c" /* type-3, 32 bits */ "%c%c%c%c" /* LanManager length twice */ "%c%c%c%c" /* LanManager length + allocated space */ "%c%c" /* LanManager offset */ "%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" /* 2 zeroes */ "%c%c" /* domain length */ "%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 length */ "%c%c" /* user allocated space */ "%c%c" /* user offset */ "%c%c" /* 2 zeroes */ "%c%c" /* host length */ "%c%c" /* host length */ "%c%c" /* host allocated space */ "%c%c" /* host offset */ "%c%c%c%c%c%c" /* 6 zeroes */ Loading @@ -467,16 +437,21 @@ CURLcode Curl_output_ntlm(struct connectdata *conn) /* LanManager response */ /* NT response */ , 0, 0,0,0, 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, #ifdef USE_NTRESPONSES SHORTPAIR(0x18), /* NT-response length, twice */ SHORTPAIR(0x18), #else 0x0, 0x0, 0x0, 0x0, #endif SHORTPAIR(ntrespoff), 0x0, 0x0, Loading @@ -503,50 +478,25 @@ CURLcode Curl_output_ntlm(struct connectdata *conn) size=64; ntlm[62]=ntlm[63]=0; #if 1 ascii_to_unicode(&ntlm[size], (unsigned char *)domain, TRUE); size += domlen; ascii_to_unicode(&ntlm[size], (unsigned char *)data->state.user, FALSE); memcpy(&ntlm[size], data->state.user, 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 */ if(size < ((int)sizeof(ntlm) - 0x18)) { memcpy(&ntlm[size], lmresp, 0x18); size += 0x18; } #ifdef USE_NTRESPONSES if(size < ((int)sizeof(ntlm) - 0x18)) { memcpy(&ntlm[size], ntresp, 0x18); size += 0x18; } #endif ntlm[56] = size & 0xff; 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 */ size = Curl_base64_encode(ntlm, size, &base64); Loading @@ -560,15 +510,17 @@ CURLcode Curl_output_ntlm(struct connectdata *conn) 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, * don't send a header in future requests */ if(conn->allocptr.userpwd) { free(conn->allocptr.userpwd); conn->allocptr.userpwd=NULL; } } break; } return CURLE_OK; Loading Loading
lib/http_ntlm.c +131 −179 Original line number Diff line number Diff line Loading @@ -22,7 +22,12 @@ ***************************************************************************/ #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 #ifdef USE_SSLEAY Loading Loading @@ -65,23 +70,23 @@ #endif /* The last #include file should be: */ #ifdef MALLOCDEBUG #ifdef CURLDEBUG #include "memdebug.h" #endif /* The one and only master resource for NTLM "hacking": /* Define this to make the type-3 message include the NT response message */ #undef USE_NTRESPONSES ====> http://www.innovation.ch/java/ntlm.html <==== /* (*) = A "security buffer" is a triplet consisting of two shorts and one long: Brought to the world by Ronald Tschalr. 1. a 'short' containing the length of the buffer 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 from the beginning of the NTLM message, in bytes. */ /* Test example header: WWW-Authenticate: NTLM */ CURLntlm Curl_input_ntlm(struct connectdata *conn, char *header) /* rest of the www-authenticate: Loading @@ -101,31 +106,18 @@ CURLntlm Curl_input_ntlm(struct connectdata *conn, 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: 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. /* We got a type-2 message here: 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); Loading @@ -135,6 +127,9 @@ requests show that 0x18-0x1f seems to be the nonce anyway. if(size >= 48) /* the nonce of interest is index [24 .. 31], 8 bytes */ memcpy(data->state.ntlm.nonce, &buffer[24], 8); /* at index decimal 20, there's a 32bit NTLM flag field */ } else { if(data->state.ntlm.state >= NTLMSTATE_TYPE1) Loading Loading @@ -198,12 +193,16 @@ static void calc_resp(unsigned char *keys, */ static void mkhash(char *password, unsigned char *nonce, /* 8 bytes */ unsigned char *lmresp, /* must fit 0x18 bytes */ unsigned char *ntresp) /* must fit 0x18 bytes */ unsigned char *lmresp /* must fit 0x18 bytes */ #ifdef USE_NTRESPONSES , unsigned char *ntresp /* must fit 0x18 bytes */ #endif ) { unsigned char lmbuffer[21]; #ifdef USE_NTRESPONSES unsigned char ntbuffer[21]; #endif unsigned char *pw; static const unsigned char magic[] = { 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 Loading Loading @@ -239,7 +238,10 @@ static void mkhash(char *password, memset(lmbuffer+16, 0, 5); } /* create LM responses */ calc_resp(lmbuffer, nonce, lmresp); #ifdef USE_NTRESPONSES { /* create NT hashed password */ MD4_CTX MD4; Loading @@ -258,35 +260,22 @@ static void mkhash(char *password, memset(ntbuffer+16, 0, 8); } /* create responses */ calc_resp(lmbuffer, nonce, lmresp); calc_resp(ntbuffer, nonce, ntresp); #endif 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 LONGQUARTET(x) ((x) & 0xff), (((x) >> 8)&0xff), \ (((x) >>16)&0xff), ((x)>>24) /* this is for creating ntlm header output */ CURLcode Curl_output_ntlm(struct connectdata *conn) { struct SessionHandle *data=conn->data; const char *domain="CURL"; const char *host="HAXX"; const char *domain=""; /* empty */ const char *host=""; /* empty */ int domlen=strlen(domain); int hostlen = strlen(host); int hostoff; /* host name offset */ Loading @@ -295,49 +284,46 @@ CURLcode Curl_output_ntlm(struct connectdata *conn) char *base64=NULL; 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; domoff = hostoff + hostlen; /* IE used this as type-1 maessage: /* Create and send a type-1 message: Authorization: NTLM \ TlRMTVNTUAABAAAABoIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAAAAAAAwAAAA\r\n This translates into: 0x00: 4e 54 4c 4d 53 53 50 00 01 00 00 00 06 82 00 00 | NTLMSSP......... 0x10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................ 0x20: 00 00 00 00 30 00 00 00 00 00 00 00 30 00 00 00 | ....0.......0... 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 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 start of data block */ snprintf((char *)ntlm, sizeof(ntlm), "NTLMSSP%c" "\x01" /* type 1 */ "%c%c%c" "\x03\xb2" "%c%c" "%c%c" /* domain length */ "\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 length */ "%c%c" /* host allocated space */ "%c%c" /* host name offset */ "%c%c" /* 2 zeroes */ "%s" /* host name */ "%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(domoff), Loading @@ -350,11 +336,7 @@ CURLcode Curl_output_ntlm(struct connectdata *conn) /* initial packet length */ 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 */ size = Curl_base64_encode(ntlm, size, &base64); Loading @@ -365,55 +347,43 @@ CURLcode Curl_output_ntlm(struct connectdata *conn) } else 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 */ /* My test-IE session sent this type-3: TlRMTVNTUAADAAAAGAAYAEoAAAAAAAAAYgAAAAUABQA0AAAABgAGADk\ AAAALAAsAPwAAAEhFTU1BZGFuaWVsTElMTEFTWVNURVJPVPJELoebUg\ 4SvW0ed2QmKu0SjX4qNrI= Which translates to: 0x00: 4e 54 4c 4d 53 53 50 00 03 00 00 00 18 00 18 00 | NTLMSSP......... 0x10: 4a 00 00 00 00 00 00 00 62 00 00 00 05 00 05 00 | J.......b....... 0x20: 34 00 00 00 06 00 06 00 39 00 00 00 0b 00 0b 00 | 4.......9....... 0x30: 3f 00 00 00 48 45 4d 4d 41 64 61 6e 69 65 6c 4c | ?...HEMMAdanielL 0x40: 49 4c 4c 41 53 59 53 54 45 52 4f 54 f2 44 2e 87 | ILLASYSTEROT.D.. 0x50: 9b 52 0e 12 bd 6d 1e 77 64 26 2a ed 12 8d 7e 2a | .R...m.wd&*...~* 0x60: 36 b2 | 6. Note how the domain + username + hostname ARE NOT unicoded in any way. Domain and hostname are uppercase, while username are case sensitive. 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. break; case NTLMSTATE_TYPE2: /* We received the type-2 already, create a type-3 message: 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 Domain Name security buffer(*) 36 User Name security buffer(*) 44 Workstation Name security buffer(*) (52) Session Key (optional) security buffer(*) (60) Flags (optional) long 52 (64) start of data block */ { int lmrespoff; int ntrespoff; int useroff; unsigned char lmresp[0x18]; /* fixed-size */ #ifdef USE_NTRESPONSES unsigned char ntresp[0x18]; /* fixed-size */ #endif 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 */ domlen *= 2; Loading @@ -429,29 +399,29 @@ CURLcode Curl_output_ntlm(struct connectdata *conn) /* Create the big type-3 message binary blob */ size = snprintf((char *)ntlm, sizeof(ntlm), "NTLMSSP%c" "\x03" /* type 3 */ "%c%c%c" /* 3 zeroes */ "\x03%c%c%c" /* type-3, 32 bits */ "%c%c%c%c" /* LanManager length twice */ "%c%c%c%c" /* LanManager length + allocated space */ "%c%c" /* LanManager offset */ "%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" /* 2 zeroes */ "%c%c" /* domain length */ "%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 length */ "%c%c" /* user allocated space */ "%c%c" /* user offset */ "%c%c" /* 2 zeroes */ "%c%c" /* host length */ "%c%c" /* host length */ "%c%c" /* host allocated space */ "%c%c" /* host offset */ "%c%c%c%c%c%c" /* 6 zeroes */ Loading @@ -467,16 +437,21 @@ CURLcode Curl_output_ntlm(struct connectdata *conn) /* LanManager response */ /* NT response */ , 0, 0,0,0, 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, #ifdef USE_NTRESPONSES SHORTPAIR(0x18), /* NT-response length, twice */ SHORTPAIR(0x18), #else 0x0, 0x0, 0x0, 0x0, #endif SHORTPAIR(ntrespoff), 0x0, 0x0, Loading @@ -503,50 +478,25 @@ CURLcode Curl_output_ntlm(struct connectdata *conn) size=64; ntlm[62]=ntlm[63]=0; #if 1 ascii_to_unicode(&ntlm[size], (unsigned char *)domain, TRUE); size += domlen; ascii_to_unicode(&ntlm[size], (unsigned char *)data->state.user, FALSE); memcpy(&ntlm[size], data->state.user, 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 */ if(size < ((int)sizeof(ntlm) - 0x18)) { memcpy(&ntlm[size], lmresp, 0x18); size += 0x18; } #ifdef USE_NTRESPONSES if(size < ((int)sizeof(ntlm) - 0x18)) { memcpy(&ntlm[size], ntresp, 0x18); size += 0x18; } #endif ntlm[56] = size & 0xff; 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 */ size = Curl_base64_encode(ntlm, size, &base64); Loading @@ -560,15 +510,17 @@ CURLcode Curl_output_ntlm(struct connectdata *conn) 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, * don't send a header in future requests */ if(conn->allocptr.userpwd) { free(conn->allocptr.userpwd); conn->allocptr.userpwd=NULL; } } break; } return CURLE_OK; Loading