1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2008, Daniel Stenberg, <daniel@haxx.se>, et al.
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at http://curl.haxx.se/docs/copyright.html.
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 * $Id: http_ntlm.c,v 1.1.1.1 2008-09-23 16:32:05 hoffman Exp $
22 ***************************************************************************/
27 http://davenport.sourceforge.net/ntlm.html
28 http://www.innovation.ch/java/ntlm.html
30 Another implementation:
31 http://lxr.mozilla.org/mozilla/source/security/manager/ssl/src/nsNTLMAuthModule.cpp
35 #ifndef CURL_DISABLE_HTTP
40 /* -- WIN32 approved -- */
51 #if (defined(NETWARE) && !defined(__NOVELL_LIBC__))
56 #include "easyif.h" /* for Curl_convert_... prototypes */
59 #include "curl_base64.h"
60 #include "http_ntlm.h"
65 #define _MPRINTF_REPLACE /* use our functions only */
66 #include <curl/mprintf.h>
68 /* "NTLMSSP" signature is always in ASCII regardless of the platform */
69 #define NTLMSSP_SIGNATURE "\x4e\x54\x4c\x4d\x53\x53\x50"
71 #ifndef USE_WINDOWS_SSPI
75 # include <openssl/des.h>
76 # include <openssl/md4.h>
77 # include <openssl/md5.h>
78 # include <openssl/ssl.h>
79 # include <openssl/rand.h>
88 # error "Can't compile NTLM support without OpenSSL."
91 #if OPENSSL_VERSION_NUMBER < 0x00907001L
92 #define DES_key_schedule des_key_schedule
93 #define DES_cblock des_cblock
94 #define DES_set_odd_parity des_set_odd_parity
95 #define DES_set_key des_set_key
96 #define DES_ecb_encrypt des_ecb_encrypt
98 /* This is how things were done in the old days */
100 #define DESKEYARG(x) x
103 #define DESKEYARG(x) *x
111 /* Handle of security.dll or secur32.dll, depending on Windows version */
112 static HMODULE s_hSecDll
= NULL
;
113 /* Pointer to SSPI dispatch table */
114 static PSecurityFunctionTable s_pSecFn
= NULL
;
118 /* The last #include file should be: */
119 #include "memdebug.h"
121 /* Define this to make the type-3 message include the NT response message */
122 #define USE_NTRESPONSES 1
124 /* Define this to make the type-3 message include the NTLM2Session response
125 message, requires USE_NTRESPONSES. */
126 #define USE_NTLM2SESSION 1
128 #ifndef USE_WINDOWS_SSPI
129 /* this function converts from the little endian format used in the incoming
130 package to whatever endian format we're using natively */
131 static unsigned int readint_le(unsigned char *buf
) /* must point to a
134 return ((unsigned int)buf
[0]) | ((unsigned int)buf
[1] << 8) |
135 ((unsigned int)buf
[2] << 16) | ((unsigned int)buf
[3] << 24);
140 # define DEBUG_OUT(x) x
141 static void print_flags(FILE *handle
, unsigned long flags
)
143 if(flags
& NTLMFLAG_NEGOTIATE_UNICODE
)
144 fprintf(handle
, "NTLMFLAG_NEGOTIATE_UNICODE ");
145 if(flags
& NTLMFLAG_NEGOTIATE_OEM
)
146 fprintf(handle
, "NTLMFLAG_NEGOTIATE_OEM ");
147 if(flags
& NTLMFLAG_REQUEST_TARGET
)
148 fprintf(handle
, "NTLMFLAG_REQUEST_TARGET ");
150 fprintf(handle
, "NTLMFLAG_UNKNOWN_3 ");
151 if(flags
& NTLMFLAG_NEGOTIATE_SIGN
)
152 fprintf(handle
, "NTLMFLAG_NEGOTIATE_SIGN ");
153 if(flags
& NTLMFLAG_NEGOTIATE_SEAL
)
154 fprintf(handle
, "NTLMFLAG_NEGOTIATE_SEAL ");
155 if(flags
& NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE
)
156 fprintf(handle
, "NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE ");
157 if(flags
& NTLMFLAG_NEGOTIATE_LM_KEY
)
158 fprintf(handle
, "NTLMFLAG_NEGOTIATE_LM_KEY ");
159 if(flags
& NTLMFLAG_NEGOTIATE_NETWARE
)
160 fprintf(handle
, "NTLMFLAG_NEGOTIATE_NETWARE ");
161 if(flags
& NTLMFLAG_NEGOTIATE_NTLM_KEY
)
162 fprintf(handle
, "NTLMFLAG_NEGOTIATE_NTLM_KEY ");
164 fprintf(handle
, "NTLMFLAG_UNKNOWN_10 ");
165 if(flags
& NTLMFLAG_NEGOTIATE_ANONYMOUS
)
166 fprintf(handle
, "NTLMFLAG_NEGOTIATE_ANONYMOUS ");
167 if(flags
& NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED
)
168 fprintf(handle
, "NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED ");
169 if(flags
& NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED
)
170 fprintf(handle
, "NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED ");
171 if(flags
& NTLMFLAG_NEGOTIATE_LOCAL_CALL
)
172 fprintf(handle
, "NTLMFLAG_NEGOTIATE_LOCAL_CALL ");
173 if(flags
& NTLMFLAG_NEGOTIATE_ALWAYS_SIGN
)
174 fprintf(handle
, "NTLMFLAG_NEGOTIATE_ALWAYS_SIGN ");
175 if(flags
& NTLMFLAG_TARGET_TYPE_DOMAIN
)
176 fprintf(handle
, "NTLMFLAG_TARGET_TYPE_DOMAIN ");
177 if(flags
& NTLMFLAG_TARGET_TYPE_SERVER
)
178 fprintf(handle
, "NTLMFLAG_TARGET_TYPE_SERVER ");
179 if(flags
& NTLMFLAG_TARGET_TYPE_SHARE
)
180 fprintf(handle
, "NTLMFLAG_TARGET_TYPE_SHARE ");
181 if(flags
& NTLMFLAG_NEGOTIATE_NTLM2_KEY
)
182 fprintf(handle
, "NTLMFLAG_NEGOTIATE_NTLM2_KEY ");
183 if(flags
& NTLMFLAG_REQUEST_INIT_RESPONSE
)
184 fprintf(handle
, "NTLMFLAG_REQUEST_INIT_RESPONSE ");
185 if(flags
& NTLMFLAG_REQUEST_ACCEPT_RESPONSE
)
186 fprintf(handle
, "NTLMFLAG_REQUEST_ACCEPT_RESPONSE ");
187 if(flags
& NTLMFLAG_REQUEST_NONNT_SESSION_KEY
)
188 fprintf(handle
, "NTLMFLAG_REQUEST_NONNT_SESSION_KEY ");
189 if(flags
& NTLMFLAG_NEGOTIATE_TARGET_INFO
)
190 fprintf(handle
, "NTLMFLAG_NEGOTIATE_TARGET_INFO ");
192 fprintf(handle
, "NTLMFLAG_UNKNOWN_24 ");
194 fprintf(handle
, "NTLMFLAG_UNKNOWN_25 ");
196 fprintf(handle
, "NTLMFLAG_UNKNOWN_26 ");
198 fprintf(handle
, "NTLMFLAG_UNKNOWN_27 ");
200 fprintf(handle
, "NTLMFLAG_UNKNOWN_28 ");
201 if(flags
& NTLMFLAG_NEGOTIATE_128
)
202 fprintf(handle
, "NTLMFLAG_NEGOTIATE_128 ");
203 if(flags
& NTLMFLAG_NEGOTIATE_KEY_EXCHANGE
)
204 fprintf(handle
, "NTLMFLAG_NEGOTIATE_KEY_EXCHANGE ");
205 if(flags
& NTLMFLAG_NEGOTIATE_56
)
206 fprintf(handle
, "NTLMFLAG_NEGOTIATE_56 ");
209 static void print_hex(FILE *handle
, const char *buf
, size_t len
)
212 fprintf(stderr
, "0x");
214 fprintf(stderr
, "%02.2x", (unsigned int)*p
++);
217 # define DEBUG_OUT(x)
221 (*) = A "security buffer" is a triplet consisting of two shorts and one
224 1. a 'short' containing the length of the buffer in bytes
225 2. a 'short' containing the allocated space for the buffer in bytes
226 3. a 'long' containing the offset to the start of the buffer from the
227 beginning of the NTLM message, in bytes.
231 CURLntlm
Curl_input_ntlm(struct connectdata
*conn
,
232 bool proxy
, /* if proxy or not */
233 const char *header
) /* rest of the www-authenticate:
236 /* point to the correct struct with this */
237 struct ntlmdata
*ntlm
;
238 #ifndef USE_WINDOWS_SSPI
239 static const char type2_marker
[] = { 0x02, 0x00, 0x00, 0x00 };
242 ntlm
= proxy
?&conn
->proxyntlm
:&conn
->ntlm
;
244 /* skip initial whitespaces */
245 while(*header
&& ISSPACE(*header
))
248 if(checkprefix("NTLM", header
)) {
249 header
+= strlen("NTLM");
251 while(*header
&& ISSPACE(*header
))
255 /* We got a type-2 message here:
257 Index Description Content
258 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
260 8 NTLM Message Type long (0x02000000)
261 12 Target Name security buffer(*)
264 (32) Context (optional) 8 bytes (two consecutive longs)
265 (40) Target Information (optional) security buffer(*)
266 32 (48) start of data block
269 unsigned char *buffer
;
270 size
= Curl_base64_decode(header
, &buffer
);
274 ntlm
->state
= NTLMSTATE_TYPE2
; /* we got a type-2 */
276 #ifdef USE_WINDOWS_SSPI
277 ntlm
->type_2
= malloc(size
+1);
278 if(ntlm
->type_2
== NULL
) {
280 return CURLE_OUT_OF_MEMORY
;
282 ntlm
->n_type_2
= size
;
283 memcpy(ntlm
->type_2
, buffer
, size
);
288 (memcmp(buffer
, NTLMSSP_SIGNATURE
, 8) != 0) ||
289 (memcmp(buffer
+8, type2_marker
, sizeof(type2_marker
)) != 0)) {
290 /* This was not a good enough type-2 message */
295 ntlm
->flags
= readint_le(&buffer
[20]);
296 memcpy(ntlm
->nonce
, &buffer
[24], 8);
299 fprintf(stderr
, "**** TYPE2 header flags=0x%08.8lx ", ntlm
->flags
);
300 print_flags(stderr
, ntlm
->flags
);
301 fprintf(stderr
, "\n nonce=");
302 print_hex(stderr
, (char *)ntlm
->nonce
, 8);
303 fprintf(stderr
, "\n****\n");
304 fprintf(stderr
, "**** Header %s\n ", header
);
311 if(ntlm
->state
>= NTLMSTATE_TYPE1
)
314 ntlm
->state
= NTLMSTATE_TYPE1
; /* we should sent away a type-1 */
317 return CURLNTLM_FINE
;
320 #ifndef USE_WINDOWS_SSPI
323 * Turns a 56 bit key into the 64 bit, odd parity key and sets the key. The
324 * key schedule ks is also set.
326 static void setup_des_key(unsigned char *key_56
,
327 DES_key_schedule
DESKEYARG(ks
))
332 key
[1] = (unsigned char)(((key_56
[0] << 7) & 0xFF) | (key_56
[1] >> 1));
333 key
[2] = (unsigned char)(((key_56
[1] << 6) & 0xFF) | (key_56
[2] >> 2));
334 key
[3] = (unsigned char)(((key_56
[2] << 5) & 0xFF) | (key_56
[3] >> 3));
335 key
[4] = (unsigned char)(((key_56
[3] << 4) & 0xFF) | (key_56
[4] >> 4));
336 key
[5] = (unsigned char)(((key_56
[4] << 3) & 0xFF) | (key_56
[5] >> 5));
337 key
[6] = (unsigned char)(((key_56
[5] << 2) & 0xFF) | (key_56
[6] >> 6));
338 key
[7] = (unsigned char) ((key_56
[6] << 1) & 0xFF);
340 DES_set_odd_parity(&key
);
341 DES_set_key(&key
, ks
);
345 * takes a 21 byte array and treats it as 3 56-bit DES keys. The
346 * 8 byte plaintext is encrypted with each key and the resulting 24
347 * bytes are stored in the results array.
349 static void lm_resp(unsigned char *keys
,
350 unsigned char *plaintext
,
351 unsigned char *results
)
355 setup_des_key(keys
, DESKEY(ks
));
356 DES_ecb_encrypt((DES_cblock
*) plaintext
, (DES_cblock
*) results
,
357 DESKEY(ks
), DES_ENCRYPT
);
359 setup_des_key(keys
+7, DESKEY(ks
));
360 DES_ecb_encrypt((DES_cblock
*) plaintext
, (DES_cblock
*) (results
+8),
361 DESKEY(ks
), DES_ENCRYPT
);
363 setup_des_key(keys
+14, DESKEY(ks
));
364 DES_ecb_encrypt((DES_cblock
*) plaintext
, (DES_cblock
*) (results
+16),
365 DESKEY(ks
), DES_ENCRYPT
);
370 * Set up lanmanager hashed password
372 static void mk_lm_hash(struct SessionHandle
*data
,
374 unsigned char *lmbuffer
/* 21 bytes */)
376 unsigned char pw
[14];
377 static const unsigned char magic
[] = {
378 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 /* i.e. KGS!@#$% */
381 size_t len
= strlen(password
);
386 for (i
=0; i
<len
; i
++)
387 pw
[i
] = (unsigned char)toupper(password
[i
]);
392 #ifdef CURL_DOES_CONVERSIONS
394 * The LanManager hashed password needs to be created using the
395 * password in the network encoding not the host encoding.
398 Curl_convert_to_network(data
, (char *)pw
, 14);
404 /* Create LanManager hashed password. */
408 setup_des_key(pw
, DESKEY(ks
));
409 DES_ecb_encrypt((DES_cblock
*)magic
, (DES_cblock
*)lmbuffer
,
410 DESKEY(ks
), DES_ENCRYPT
);
412 setup_des_key(pw
+7, DESKEY(ks
));
413 DES_ecb_encrypt((DES_cblock
*)magic
, (DES_cblock
*)(lmbuffer
+8),
414 DESKEY(ks
), DES_ENCRYPT
);
416 memset(lmbuffer
+ 16, 0, 21 - 16);
421 static void utf8_to_unicode_le(unsigned char *dest
, const char *src
,
425 for (i
=0; i
<srclen
; i
++) {
426 dest
[2*i
] = (unsigned char)src
[i
];
432 * Set up nt hashed passwords
434 static CURLcode
mk_nt_hash(struct SessionHandle
*data
,
436 unsigned char *ntbuffer
/* 21 bytes */)
438 size_t len
= strlen(password
);
439 unsigned char *pw
= malloc(len
*2);
441 return CURLE_OUT_OF_MEMORY
;
443 utf8_to_unicode_le(pw
, password
, len
);
445 #ifdef CURL_DOES_CONVERSIONS
447 * The NT hashed password needs to be created using the
448 * password in the network encoding not the host encoding.
451 Curl_convert_to_network(data
, (char *)pw
, len
*2);
457 /* Create NT hashed password. */
461 MD4_Update(&MD4pw
, pw
, 2*len
);
462 MD4_Final(ntbuffer
, &MD4pw
);
464 memset(ntbuffer
+ 16, 0, 21 - 16);
475 #ifdef USE_WINDOWS_SSPI
478 ntlm_sspi_cleanup(struct ntlmdata
*ntlm
)
484 if(ntlm
->has_handles
) {
485 s_pSecFn
->DeleteSecurityContext(&ntlm
->c_handle
);
486 s_pSecFn
->FreeCredentialsHandle(&ntlm
->handle
);
487 ntlm
->has_handles
= 0;
489 if(ntlm
->p_identity
) {
490 if(ntlm
->identity
.User
) free(ntlm
->identity
.User
);
491 if(ntlm
->identity
.Password
) free(ntlm
->identity
.Password
);
492 if(ntlm
->identity
.Domain
) free(ntlm
->identity
.Domain
);
493 ntlm
->p_identity
= NULL
;
499 #define SHORTPAIR(x) ((x) & 0xff), (((x) >> 8) & 0xff)
500 #define LONGQUARTET(x) ((x) & 0xff), (((x) >> 8)&0xff), \
501 (((x) >>16)&0xff), (((x)>>24) & 0xff)
503 #define HOSTNAME_MAX 1024
505 /* this is for creating ntlm header output */
506 CURLcode
Curl_output_ntlm(struct connectdata
*conn
,
509 const char *domain
=""; /* empty */
510 char host
[HOSTNAME_MAX
+ 1] = ""; /* empty */
511 #ifndef USE_WINDOWS_SSPI
512 size_t domlen
= strlen(domain
);
513 size_t hostlen
= strlen(host
);
514 size_t hostoff
; /* host name offset */
515 size_t domoff
; /* domain name offset */
519 unsigned char ntlmbuf
[1024]; /* enough, unless the user+host+domain is very
522 /* point to the address of the pointer that holds the string to sent to the
523 server, which is for a plain host or for a HTTP proxy */
526 /* point to the name and password for this */
529 /* point to the correct struct with this */
530 struct ntlmdata
*ntlm
;
534 DEBUGASSERT(conn
->data
);
537 allocuserpwd
= &conn
->allocptr
.proxyuserpwd
;
538 userp
= conn
->proxyuser
;
539 passwdp
= conn
->proxypasswd
;
540 ntlm
= &conn
->proxyntlm
;
541 authp
= &conn
->data
->state
.authproxy
;
544 allocuserpwd
= &conn
->allocptr
.userpwd
;
546 passwdp
= conn
->passwd
;
548 authp
= &conn
->data
->state
.authhost
;
552 /* not set means empty */
559 #ifdef USE_WINDOWS_SSPI
560 if (s_hSecDll
== NULL
) {
561 /* not thread safe and leaks - use curl_global_init() to avoid */
562 CURLcode err
= Curl_ntlm_global_init();
563 if (s_hSecDll
== NULL
)
568 switch(ntlm
->state
) {
569 case NTLMSTATE_TYPE1
:
570 default: /* for the weird cases we (re)start here */
571 #ifdef USE_WINDOWS_SSPI
575 SECURITY_STATUS status
;
579 TimeStamp tsDummy
; /* For Windows 9x compatibility of SPPI calls */
581 ntlm_sspi_cleanup(ntlm
);
583 user
= strchr(userp
, '\\');
585 user
= strchr(userp
, '/');
589 domlen
= user
- userp
;
599 /* note: initialize all of this before doing the mallocs so that
600 * it can be cleaned up later without leaking memory.
602 ntlm
->p_identity
= &ntlm
->identity
;
603 memset(ntlm
->p_identity
, 0, sizeof(*ntlm
->p_identity
));
604 if((ntlm
->identity
.User
= (unsigned char *)strdup(user
)) == NULL
)
605 return CURLE_OUT_OF_MEMORY
;
606 ntlm
->identity
.UserLength
= strlen(user
);
607 if((ntlm
->identity
.Password
= (unsigned char *)strdup(passwdp
)) == NULL
)
608 return CURLE_OUT_OF_MEMORY
;
609 ntlm
->identity
.PasswordLength
= strlen(passwdp
);
610 if((ntlm
->identity
.Domain
= malloc(domlen
+1)) == NULL
)
611 return CURLE_OUT_OF_MEMORY
;
612 strncpy((char *)ntlm
->identity
.Domain
, domain
, domlen
);
613 ntlm
->identity
.Domain
[domlen
] = '\0';
614 ntlm
->identity
.DomainLength
= domlen
;
615 ntlm
->identity
.Flags
= SEC_WINNT_AUTH_IDENTITY_ANSI
;
618 ntlm
->p_identity
= NULL
;
621 if(s_pSecFn
->AcquireCredentialsHandle(
622 NULL
, (char *)"NTLM", SECPKG_CRED_OUTBOUND
, NULL
, ntlm
->p_identity
,
623 NULL
, NULL
, &ntlm
->handle
, &tsDummy
625 return CURLE_OUT_OF_MEMORY
;
628 desc
.ulVersion
= SECBUFFER_VERSION
;
630 desc
.pBuffers
= &buf
;
631 buf
.cbBuffer
= sizeof(ntlmbuf
);
632 buf
.BufferType
= SECBUFFER_TOKEN
;
633 buf
.pvBuffer
= ntlmbuf
;
635 status
= s_pSecFn
->InitializeSecurityContext(&ntlm
->handle
, NULL
,
637 ISC_REQ_CONFIDENTIALITY
|
638 ISC_REQ_REPLAY_DETECT
|
640 0, SECURITY_NETWORK_DREP
,
642 &ntlm
->c_handle
, &desc
,
645 if(status
== SEC_I_COMPLETE_AND_CONTINUE
||
646 status
== SEC_I_CONTINUE_NEEDED
) {
647 s_pSecFn
->CompleteAuthToken(&ntlm
->c_handle
, &desc
);
649 else if(status
!= SEC_E_OK
) {
650 s_pSecFn
->FreeCredentialsHandle(&ntlm
->handle
);
651 return CURLE_RECV_ERROR
;
654 ntlm
->has_handles
= 1;
659 domoff
= hostoff
+ hostlen
; /* This is 0: remember that host and domain
662 /* Create and send a type-1 message:
664 Index Description Content
665 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
667 8 NTLM Message Type long (0x01000000)
669 16 Supplied Domain security buffer(*)
670 24 Supplied Workstation security buffer(*)
671 32 start of data block
675 #define NTLM2FLAG NTLMFLAG_NEGOTIATE_NTLM2_KEY
679 snprintf((char *)ntlmbuf
, sizeof(ntlmbuf
), NTLMSSP_SIGNATURE
"%c"
680 "\x01%c%c%c" /* 32-bit type = 1 */
681 "%c%c%c%c" /* 32-bit NTLM flag field */
682 "%c%c" /* domain length */
683 "%c%c" /* domain allocated space */
684 "%c%c" /* domain name offset */
685 "%c%c" /* 2 zeroes */
686 "%c%c" /* host length */
687 "%c%c" /* host allocated space */
688 "%c%c" /* host name offset */
689 "%c%c" /* 2 zeroes */
691 "%s", /* domain string */
692 0, /* trailing zero */
693 0,0,0, /* part of type-1 long */
696 NTLMFLAG_NEGOTIATE_OEM
|
697 NTLMFLAG_REQUEST_TARGET
|
698 NTLMFLAG_NEGOTIATE_NTLM_KEY
|
700 NTLMFLAG_NEGOTIATE_ALWAYS_SIGN
710 host
/* this is empty */, domain
/* this is empty */);
712 /* initial packet length */
713 size
= 32 + hostlen
+ domlen
;
717 fprintf(stderr
, "**** TYPE1 header flags=0x%02.2x%02.2x%02.2x%02.2x 0x%08.8x ",
718 LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM
|
719 NTLMFLAG_REQUEST_TARGET
|
720 NTLMFLAG_NEGOTIATE_NTLM_KEY
|
722 NTLMFLAG_NEGOTIATE_ALWAYS_SIGN
),
723 NTLMFLAG_NEGOTIATE_OEM
|
724 NTLMFLAG_REQUEST_TARGET
|
725 NTLMFLAG_NEGOTIATE_NTLM_KEY
|
727 NTLMFLAG_NEGOTIATE_ALWAYS_SIGN
);
729 NTLMFLAG_NEGOTIATE_OEM
|
730 NTLMFLAG_REQUEST_TARGET
|
731 NTLMFLAG_NEGOTIATE_NTLM_KEY
|
733 NTLMFLAG_NEGOTIATE_ALWAYS_SIGN
);
734 fprintf(stderr
, "\n****\n");
737 /* now size is the size of the base64 encoded package size */
738 size
= Curl_base64_encode(NULL
, (char *)ntlmbuf
, size
, &base64
);
741 Curl_safefree(*allocuserpwd
);
742 *allocuserpwd
= aprintf("%sAuthorization: NTLM %s\r\n",
745 DEBUG_OUT(fprintf(stderr
, "**** Header %s\n ", *allocuserpwd
));
749 return CURLE_OUT_OF_MEMORY
; /* FIX TODO */
753 case NTLMSTATE_TYPE2
:
754 /* We received the type-2 message already, create a type-3 message:
756 Index Description Content
757 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
759 8 NTLM Message Type long (0x03000000)
760 12 LM/LMv2 Response security buffer(*)
761 20 NTLM/NTLMv2 Response security buffer(*)
762 28 Domain Name security buffer(*)
763 36 User Name security buffer(*)
764 44 Workstation Name security buffer(*)
765 (52) Session Key (optional) security buffer(*)
766 (60) Flags (optional) long
767 52 (64) start of data block
772 #ifdef USE_WINDOWS_SSPI
773 SecBuffer type_2
, type_3
;
774 SecBufferDesc type_2_desc
, type_3_desc
;
775 SECURITY_STATUS status
;
777 TimeStamp tsDummy
; /* For Windows 9x compatibility of SPPI calls */
779 type_2_desc
.ulVersion
= type_3_desc
.ulVersion
= SECBUFFER_VERSION
;
780 type_2_desc
.cBuffers
= type_3_desc
.cBuffers
= 1;
781 type_2_desc
.pBuffers
= &type_2
;
782 type_3_desc
.pBuffers
= &type_3
;
784 type_2
.BufferType
= SECBUFFER_TOKEN
;
785 type_2
.pvBuffer
= ntlm
->type_2
;
786 type_2
.cbBuffer
= ntlm
->n_type_2
;
787 type_3
.BufferType
= SECBUFFER_TOKEN
;
788 type_3
.pvBuffer
= ntlmbuf
;
789 type_3
.cbBuffer
= sizeof(ntlmbuf
);
791 status
= s_pSecFn
->InitializeSecurityContext(&ntlm
->handle
, &ntlm
->c_handle
,
793 ISC_REQ_CONFIDENTIALITY
|
794 ISC_REQ_REPLAY_DETECT
|
796 0, SECURITY_NETWORK_DREP
, &type_2_desc
,
797 0, &ntlm
->c_handle
, &type_3_desc
,
800 if(status
!= SEC_E_OK
)
801 return CURLE_RECV_ERROR
;
803 size
= type_3
.cbBuffer
;
805 ntlm_sspi_cleanup(ntlm
);
809 unsigned char lmresp
[24]; /* fixed-size */
812 unsigned char ntresp
[24]; /* fixed-size */
818 user
= strchr(userp
, '\\');
820 user
= strchr(userp
, '/');
824 domlen
= (user
- domain
);
829 userlen
= strlen(user
);
831 if(gethostname(host
, HOSTNAME_MAX
)) {
832 infof(conn
->data
, "gethostname() failed, continuing without!");
836 /* If the workstation if configured with a full DNS name (i.e.
837 * workstation.somewhere.net) gethostname() returns the fully qualified
838 * name, which NTLM doesn't like.
840 char *dot
= strchr(host
, '.');
843 hostlen
= strlen(host
);
847 /* We don't support NTLM2 if we don't have USE_NTRESPONSES */
848 if(ntlm
->flags
& NTLMFLAG_NEGOTIATE_NTLM2_KEY
) {
849 unsigned char ntbuffer
[0x18];
850 unsigned char tmp
[0x18];
851 unsigned char md5sum
[MD5_DIGEST_LENGTH
];
853 unsigned char entropy
[8];
855 /* Need to create 8 bytes random data */
856 Curl_ossl_seed(conn
->data
); /* Initiate the seed if not already done */
857 RAND_bytes(entropy
,8);
859 /* 8 bytes random data as challenge in lmresp */
860 memcpy(lmresp
,entropy
,8);
862 memset(lmresp
+8,0,0x10);
864 /* Fill tmp with challenge(nonce?) + entropy */
865 memcpy(tmp
,&ntlm
->nonce
[0],8);
866 memcpy(tmp
+8,entropy
,8);
869 MD5_Update(&MD5pw
, tmp
, 16);
870 MD5_Final(md5sum
, &MD5pw
);
871 /* We shall only use the first 8 bytes of md5sum,
872 but the des code in lm_resp only encrypt the first 8 bytes */
873 if(mk_nt_hash(conn
->data
, passwdp
, ntbuffer
) == CURLE_OUT_OF_MEMORY
)
874 return CURLE_OUT_OF_MEMORY
;
875 lm_resp(ntbuffer
, md5sum
, ntresp
);
877 /* End of NTLM2 Session code */
883 unsigned char ntbuffer
[0x18];
885 unsigned char lmbuffer
[0x18];
888 if(mk_nt_hash(conn
->data
, passwdp
, ntbuffer
) == CURLE_OUT_OF_MEMORY
)
889 return CURLE_OUT_OF_MEMORY
;
890 lm_resp(ntbuffer
, &ntlm
->nonce
[0], ntresp
);
893 mk_lm_hash(conn
->data
, passwdp
, lmbuffer
);
894 lm_resp(lmbuffer
, &ntlm
->nonce
[0], lmresp
);
895 /* A safer but less compatible alternative is:
896 * lm_resp(ntbuffer, &ntlm->nonce[0], lmresp);
897 * See http://davenport.sourceforge.net/ntlm.html#ntlmVersion2 */
902 lmrespoff
= 64; /* size of the message header */
904 ntrespoff
= lmrespoff
+ 0x18;
905 domoff
= ntrespoff
+ 0x18;
907 domoff
= lmrespoff
+ 0x18;
909 useroff
= domoff
+ domlen
;
910 hostoff
= useroff
+ userlen
;
913 * In the case the server sets the flag NTLMFLAG_NEGOTIATE_UNICODE, we
914 * need to filter it off because libcurl doesn't UNICODE encode the
915 * strings it packs into the NTLM authenticate packet.
917 ntlm
->flags
&= ~NTLMFLAG_NEGOTIATE_UNICODE
;
919 /* Create the big type-3 message binary blob */
920 size
= snprintf((char *)ntlmbuf
, sizeof(ntlmbuf
),
921 NTLMSSP_SIGNATURE
"%c"
922 "\x03%c%c%c" /* type-3, 32 bits */
924 "%c%c" /* LanManager length */
925 "%c%c" /* LanManager allocated space */
926 "%c%c" /* LanManager offset */
927 "%c%c" /* 2 zeroes */
929 "%c%c" /* NT-response length */
930 "%c%c" /* NT-response allocated space */
931 "%c%c" /* NT-response offset */
932 "%c%c" /* 2 zeroes */
934 "%c%c" /* domain length */
935 "%c%c" /* domain allocated space */
936 "%c%c" /* domain name offset */
937 "%c%c" /* 2 zeroes */
939 "%c%c" /* user length */
940 "%c%c" /* user allocated space */
941 "%c%c" /* user offset */
942 "%c%c" /* 2 zeroes */
944 "%c%c" /* host length */
945 "%c%c" /* host allocated space */
946 "%c%c" /* host offset */
947 "%c%c" /* 2 zeroes */
949 "%c%c" /* session key length (unknown purpose) */
950 "%c%c" /* session key allocated space (unknown purpose) */
951 "%c%c" /* session key offset (unknown purpose) */
952 "%c%c" /* 2 zeroes */
954 "%c%c%c%c" /* flags */
959 /* LanManager response */
962 0, /* zero termination */
963 0,0,0, /* type-3 long, the 24 upper bits */
965 SHORTPAIR(0x18), /* LanManager response length, twice */
967 SHORTPAIR(lmrespoff
),
971 SHORTPAIR(0x18), /* NT-response length, twice */
973 SHORTPAIR(ntrespoff
),
1001 LONGQUARTET(ntlm
->flags
));
1002 DEBUGASSERT(size
==64);
1004 DEBUGASSERT(size
== (size_t)lmrespoff
);
1005 /* We append the binary hashes */
1006 if(size
< (sizeof(ntlmbuf
) - 0x18)) {
1007 memcpy(&ntlmbuf
[size
], lmresp
, 0x18);
1012 fprintf(stderr
, "**** TYPE3 header lmresp=");
1013 print_hex(stderr
, (char *)&ntlmbuf
[lmrespoff
], 0x18);
1017 if(size
< (sizeof(ntlmbuf
) - 0x18)) {
1018 DEBUGASSERT(size
== (size_t)ntrespoff
);
1019 memcpy(&ntlmbuf
[size
], ntresp
, 0x18);
1024 fprintf(stderr
, "\n ntresp=");
1025 print_hex(stderr
, (char *)&ntlmbuf
[ntrespoff
], 0x18);
1031 fprintf(stderr
, "\n flags=0x%02.2x%02.2x%02.2x%02.2x 0x%08.8x ",
1032 LONGQUARTET(ntlm
->flags
), ntlm
->flags
);
1033 print_flags(stderr
, ntlm
->flags
);
1034 fprintf(stderr
, "\n****\n");
1038 /* Make sure that the domain, user and host strings fit in the target
1039 buffer before we copy them there. */
1040 if(size
+ userlen
+ domlen
+ hostlen
>= sizeof(ntlmbuf
)) {
1041 failf(conn
->data
, "user + domain + host name too big");
1042 return CURLE_OUT_OF_MEMORY
;
1045 DEBUGASSERT(size
== domoff
);
1046 memcpy(&ntlmbuf
[size
], domain
, domlen
);
1049 DEBUGASSERT(size
== useroff
);
1050 memcpy(&ntlmbuf
[size
], user
, userlen
);
1053 DEBUGASSERT(size
== hostoff
);
1054 memcpy(&ntlmbuf
[size
], host
, hostlen
);
1057 #ifdef CURL_DOES_CONVERSIONS
1058 /* convert domain, user, and host to ASCII but leave the rest as-is */
1059 if(CURLE_OK
!= Curl_convert_to_network(conn
->data
,
1060 (char *)&ntlmbuf
[domoff
],
1062 return CURLE_CONV_FAILED
;
1064 #endif /* CURL_DOES_CONVERSIONS */
1068 /* convert the binary blob into base64 */
1069 size
= Curl_base64_encode(NULL
, (char *)ntlmbuf
, size
, &base64
);
1072 Curl_safefree(*allocuserpwd
);
1073 *allocuserpwd
= aprintf("%sAuthorization: NTLM %s\r\n",
1076 DEBUG_OUT(fprintf(stderr
, "**** %s\n ", *allocuserpwd
));
1080 return CURLE_OUT_OF_MEMORY
; /* FIX TODO */
1082 ntlm
->state
= NTLMSTATE_TYPE3
; /* we sent a type-3 */
1087 case NTLMSTATE_TYPE3
:
1088 /* connection is already authenticated,
1089 * don't send a header in future requests */
1091 free(*allocuserpwd
);
1103 Curl_ntlm_cleanup(struct connectdata
*conn
)
1105 #ifdef USE_WINDOWS_SSPI
1106 ntlm_sspi_cleanup(&conn
->ntlm
);
1107 ntlm_sspi_cleanup(&conn
->proxyntlm
);
1113 #ifdef USE_WINDOWS_SSPI
1114 CURLcode
Curl_ntlm_global_init()
1116 /* If security interface is not yet initialized try to do this */
1117 if(s_hSecDll
== NULL
) {
1118 /* Determine Windows version. Security functions are located in
1119 * security.dll on WinNT 4.0 and in secur32.dll on Win9x. Win2K and XP
1120 * contain both these DLLs (security.dll just forwards calls to
1123 OSVERSIONINFO osver
;
1124 osver
.dwOSVersionInfoSize
= sizeof(osver
);
1125 GetVersionEx(&osver
);
1126 if(osver
.dwPlatformId
== VER_PLATFORM_WIN32_NT
1127 && osver
.dwMajorVersion
== 4)
1128 s_hSecDll
= LoadLibrary("security.dll");
1130 s_hSecDll
= LoadLibrary("secur32.dll");
1131 if(s_hSecDll
!= NULL
) {
1132 INIT_SECURITY_INTERFACE pInitSecurityInterface
;
1133 pInitSecurityInterface
=
1134 (INIT_SECURITY_INTERFACE
)GetProcAddress(s_hSecDll
,
1135 "InitSecurityInterfaceA");
1136 if(pInitSecurityInterface
!= NULL
)
1137 s_pSecFn
= pInitSecurityInterface();
1140 if(s_pSecFn
== NULL
)
1141 return CURLE_RECV_ERROR
;
1146 void Curl_ntlm_global_cleanup()
1148 if(s_hSecDll
!= NULL
) {
1149 FreeLibrary(s_hSecDll
);
1156 #endif /* USE_NTLM */
1157 #endif /* !CURL_DISABLE_HTTP */