1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2007, 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.2 2007-03-15 19:22:13 andy 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 -- */
52 #include "easyif.h" /* for Curl_convert_... prototypes */
56 #include "http_ntlm.h"
61 #define _MPRINTF_REPLACE /* use our functions only */
62 #include <curl/mprintf.h>
64 /* "NTLMSSP" signature is always in ASCII regardless of the platform */
65 #define NTLMSSP_SIGNATURE "\x4e\x54\x4c\x4d\x53\x53\x50"
67 #ifndef USE_WINDOWS_SSPI
69 #include <openssl/des.h>
70 #include <openssl/md4.h>
71 #include <openssl/md5.h>
72 #include <openssl/ssl.h>
73 #include <openssl/rand.h>
75 #if OPENSSL_VERSION_NUMBER < 0x00907001L
76 #define DES_key_schedule des_key_schedule
77 #define DES_cblock des_cblock
78 #define DES_set_odd_parity des_set_odd_parity
79 #define DES_set_key des_set_key
80 #define DES_ecb_encrypt des_ecb_encrypt
82 /* This is how things were done in the old days */
84 #define DESKEYARG(x) x
87 #define DESKEYARG(x) *x
95 /* Handle of security.dll or secur32.dll, depending on Windows version */
96 static HMODULE s_hSecDll
= NULL
;
97 /* Pointer to SSPI dispatch table */
98 static PSecurityFunctionTable s_pSecFn
= NULL
;
102 /* The last #include file should be: */
103 #include "memdebug.h"
105 /* Define this to make the type-3 message include the NT response message */
106 #define USE_NTRESPONSES 1
108 /* Define this to make the type-3 message include the NTLM2Session response
109 message, requires USE_NTRESPONSES. */
110 #define USE_NTLM2SESSION 1
112 #ifndef USE_WINDOWS_SSPI
113 /* this function converts from the little endian format used in the incoming
114 package to whatever endian format we're using natively */
115 static unsigned int readint_le(unsigned char *buf
) /* must point to a
118 return ((unsigned int)buf
[0]) | ((unsigned int)buf
[1] << 8) |
119 ((unsigned int)buf
[2] << 16) | ((unsigned int)buf
[3] << 24);
124 # define DEBUG_OUT(x) x
125 static void print_flags(FILE *handle
, unsigned long flags
)
127 if(flags
& NTLMFLAG_NEGOTIATE_UNICODE
)
128 fprintf(handle
, "NTLMFLAG_NEGOTIATE_UNICODE ");
129 if(flags
& NTLMFLAG_NEGOTIATE_OEM
)
130 fprintf(handle
, "NTLMFLAG_NEGOTIATE_OEM ");
131 if(flags
& NTLMFLAG_REQUEST_TARGET
)
132 fprintf(handle
, "NTLMFLAG_REQUEST_TARGET ");
134 fprintf(handle
, "NTLMFLAG_UNKNOWN_3 ");
135 if(flags
& NTLMFLAG_NEGOTIATE_SIGN
)
136 fprintf(handle
, "NTLMFLAG_NEGOTIATE_SIGN ");
137 if(flags
& NTLMFLAG_NEGOTIATE_SEAL
)
138 fprintf(handle
, "NTLMFLAG_NEGOTIATE_SEAL ");
139 if(flags
& NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE
)
140 fprintf(handle
, "NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE ");
141 if(flags
& NTLMFLAG_NEGOTIATE_LM_KEY
)
142 fprintf(handle
, "NTLMFLAG_NEGOTIATE_LM_KEY ");
143 if(flags
& NTLMFLAG_NEGOTIATE_NETWARE
)
144 fprintf(handle
, "NTLMFLAG_NEGOTIATE_NETWARE ");
145 if(flags
& NTLMFLAG_NEGOTIATE_NTLM_KEY
)
146 fprintf(handle
, "NTLMFLAG_NEGOTIATE_NTLM_KEY ");
148 fprintf(handle
, "NTLMFLAG_UNKNOWN_10 ");
150 fprintf(handle
, "NTLMFLAG_UNKNOWN_11 ");
151 if(flags
& NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED
)
152 fprintf(handle
, "NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED ");
153 if(flags
& NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED
)
154 fprintf(handle
, "NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED ");
155 if(flags
& NTLMFLAG_NEGOTIATE_LOCAL_CALL
)
156 fprintf(handle
, "NTLMFLAG_NEGOTIATE_LOCAL_CALL ");
157 if(flags
& NTLMFLAG_NEGOTIATE_ALWAYS_SIGN
)
158 fprintf(handle
, "NTLMFLAG_NEGOTIATE_ALWAYS_SIGN ");
159 if(flags
& NTLMFLAG_TARGET_TYPE_DOMAIN
)
160 fprintf(handle
, "NTLMFLAG_TARGET_TYPE_DOMAIN ");
161 if(flags
& NTLMFLAG_TARGET_TYPE_SERVER
)
162 fprintf(handle
, "NTLMFLAG_TARGET_TYPE_SERVER ");
163 if(flags
& NTLMFLAG_TARGET_TYPE_SHARE
)
164 fprintf(handle
, "NTLMFLAG_TARGET_TYPE_SHARE ");
165 if(flags
& NTLMFLAG_NEGOTIATE_NTLM2_KEY
)
166 fprintf(handle
, "NTLMFLAG_NEGOTIATE_NTLM2_KEY ");
167 if(flags
& NTLMFLAG_REQUEST_INIT_RESPONSE
)
168 fprintf(handle
, "NTLMFLAG_REQUEST_INIT_RESPONSE ");
169 if(flags
& NTLMFLAG_REQUEST_ACCEPT_RESPONSE
)
170 fprintf(handle
, "NTLMFLAG_REQUEST_ACCEPT_RESPONSE ");
171 if(flags
& NTLMFLAG_REQUEST_NONNT_SESSION_KEY
)
172 fprintf(handle
, "NTLMFLAG_REQUEST_NONNT_SESSION_KEY ");
173 if(flags
& NTLMFLAG_NEGOTIATE_TARGET_INFO
)
174 fprintf(handle
, "NTLMFLAG_NEGOTIATE_TARGET_INFO ");
176 fprintf(handle
, "NTLMFLAG_UNKNOWN_24 ");
178 fprintf(handle
, "NTLMFLAG_UNKNOWN_25 ");
180 fprintf(handle
, "NTLMFLAG_UNKNOWN_26 ");
182 fprintf(handle
, "NTLMFLAG_UNKNOWN_27 ");
184 fprintf(handle
, "NTLMFLAG_UNKNOWN_28 ");
185 if(flags
& NTLMFLAG_NEGOTIATE_128
)
186 fprintf(handle
, "NTLMFLAG_NEGOTIATE_128 ");
187 if(flags
& NTLMFLAG_NEGOTIATE_KEY_EXCHANGE
)
188 fprintf(handle
, "NTLMFLAG_NEGOTIATE_KEY_EXCHANGE ");
189 if(flags
& NTLMFLAG_NEGOTIATE_56
)
190 fprintf(handle
, "NTLMFLAG_NEGOTIATE_56 ");
193 static void print_hex(FILE *handle
, const char *buf
, size_t len
)
196 fprintf(stderr
, "0x");
198 fprintf(stderr
, "%02.2x", (unsigned int)*p
++);
201 # define DEBUG_OUT(x)
205 (*) = A "security buffer" is a triplet consisting of two shorts and one
208 1. a 'short' containing the length of the buffer in bytes
209 2. a 'short' containing the allocated space for the buffer in bytes
210 3. a 'long' containing the offset to the start of the buffer from the
211 beginning of the NTLM message, in bytes.
215 CURLntlm
Curl_input_ntlm(struct connectdata
*conn
,
216 bool proxy
, /* if proxy or not */
217 char *header
) /* rest of the www-authenticate:
220 /* point to the correct struct with this */
221 struct ntlmdata
*ntlm
;
222 #ifndef USE_WINDOWS_SSPI
223 static const char type2_marker
[] = { 0x02, 0x00, 0x00, 0x00 };
226 ntlm
= proxy
?&conn
->proxyntlm
:&conn
->ntlm
;
228 /* skip initial whitespaces */
229 while(*header
&& ISSPACE(*header
))
232 if(checkprefix("NTLM", header
)) {
233 header
+= strlen("NTLM");
235 while(*header
&& ISSPACE(*header
))
239 /* We got a type-2 message here:
241 Index Description Content
242 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
244 8 NTLM Message Type long (0x02000000)
245 12 Target Name security buffer(*)
248 (32) Context (optional) 8 bytes (two consecutive longs)
249 (40) Target Information (optional) security buffer(*)
250 32 (48) start of data block
253 unsigned char *buffer
;
254 size
= Curl_base64_decode(header
, &buffer
);
258 ntlm
->state
= NTLMSTATE_TYPE2
; /* we got a type-2 */
260 #ifdef USE_WINDOWS_SSPI
261 ntlm
->type_2
= malloc(size
+1);
262 if (ntlm
->type_2
== NULL
) {
264 return CURLE_OUT_OF_MEMORY
;
266 ntlm
->n_type_2
= size
;
267 memcpy(ntlm
->type_2
, buffer
, size
);
272 (memcmp(buffer
, NTLMSSP_SIGNATURE
, 8) != 0) ||
273 (memcmp(buffer
+8, type2_marker
, sizeof(type2_marker
)) != 0)) {
274 /* This was not a good enough type-2 message */
279 ntlm
->flags
= readint_le(&buffer
[20]);
280 memcpy(ntlm
->nonce
, &buffer
[24], 8);
283 fprintf(stderr
, "**** TYPE2 header flags=0x%08.8lx ", ntlm
->flags
);
284 print_flags(stderr
, ntlm
->flags
);
285 fprintf(stderr
, "\n nonce=");
286 print_hex(stderr
, (char *)ntlm
->nonce
, 8);
287 fprintf(stderr
, "\n****\n");
288 fprintf(stderr
, "**** Header %s\n ", header
);
295 if(ntlm
->state
>= NTLMSTATE_TYPE1
)
298 ntlm
->state
= NTLMSTATE_TYPE1
; /* we should sent away a type-1 */
301 return CURLNTLM_FINE
;
304 #ifndef USE_WINDOWS_SSPI
307 * Turns a 56 bit key into the 64 bit, odd parity key and sets the key. The
308 * key schedule ks is also set.
310 static void setup_des_key(unsigned char *key_56
,
311 DES_key_schedule
DESKEYARG(ks
))
316 key
[1] = (unsigned char)(((key_56
[0] << 7) & 0xFF) | (key_56
[1] >> 1));
317 key
[2] = (unsigned char)(((key_56
[1] << 6) & 0xFF) | (key_56
[2] >> 2));
318 key
[3] = (unsigned char)(((key_56
[2] << 5) & 0xFF) | (key_56
[3] >> 3));
319 key
[4] = (unsigned char)(((key_56
[3] << 4) & 0xFF) | (key_56
[4] >> 4));
320 key
[5] = (unsigned char)(((key_56
[4] << 3) & 0xFF) | (key_56
[5] >> 5));
321 key
[6] = (unsigned char)(((key_56
[5] << 2) & 0xFF) | (key_56
[6] >> 6));
322 key
[7] = (unsigned char) ((key_56
[6] << 1) & 0xFF);
324 DES_set_odd_parity(&key
);
325 DES_set_key(&key
, ks
);
329 * takes a 21 byte array and treats it as 3 56-bit DES keys. The
330 * 8 byte plaintext is encrypted with each key and the resulting 24
331 * bytes are stored in the results array.
333 static void lm_resp(unsigned char *keys
,
334 unsigned char *plaintext
,
335 unsigned char *results
)
339 setup_des_key(keys
, DESKEY(ks
));
340 DES_ecb_encrypt((DES_cblock
*) plaintext
, (DES_cblock
*) results
,
341 DESKEY(ks
), DES_ENCRYPT
);
343 setup_des_key(keys
+7, DESKEY(ks
));
344 DES_ecb_encrypt((DES_cblock
*) plaintext
, (DES_cblock
*) (results
+8),
345 DESKEY(ks
), DES_ENCRYPT
);
347 setup_des_key(keys
+14, DESKEY(ks
));
348 DES_ecb_encrypt((DES_cblock
*) plaintext
, (DES_cblock
*) (results
+16),
349 DESKEY(ks
), DES_ENCRYPT
);
354 * Set up lanmanager hashed password
356 static void mk_lm_hash(struct SessionHandle
*data
,
358 unsigned char *lmbuffer
/* 21 bytes */)
360 unsigned char pw
[14];
361 static const unsigned char magic
[] = {
362 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 /* i.e. KGS!@#$% */
365 size_t len
= strlen(password
);
370 for (i
=0; i
<len
; i
++)
371 pw
[i
] = (unsigned char)toupper(password
[i
]);
376 #ifdef CURL_DOES_CONVERSIONS
378 * The LanManager hashed password needs to be created using the
379 * password in the network encoding not the host encoding.
382 Curl_convert_to_network(data
, (char *)pw
, 14);
388 /* Create LanManager hashed password. */
392 setup_des_key(pw
, DESKEY(ks
));
393 DES_ecb_encrypt((DES_cblock
*)magic
, (DES_cblock
*)lmbuffer
,
394 DESKEY(ks
), DES_ENCRYPT
);
396 setup_des_key(pw
+7, DESKEY(ks
));
397 DES_ecb_encrypt((DES_cblock
*)magic
, (DES_cblock
*)(lmbuffer
+8),
398 DESKEY(ks
), DES_ENCRYPT
);
400 memset(lmbuffer
+ 16, 0, 21 - 16);
405 static void utf8_to_unicode_le(unsigned char *dest
, const char *src
,
409 for (i
=0; i
<srclen
; i
++) {
410 dest
[2*i
] = (unsigned char)src
[i
];
416 * Set up nt hashed passwords
418 static void mk_nt_hash(struct SessionHandle
*data
,
420 unsigned char *ntbuffer
/* 21 bytes */)
422 size_t len
= strlen(password
);
423 unsigned char *pw
= malloc(len
*2);
425 utf8_to_unicode_le(pw
, password
, len
);
427 #ifdef CURL_DOES_CONVERSIONS
429 * The NT hashed password needs to be created using the
430 * password in the network encoding not the host encoding.
433 Curl_convert_to_network(data
, (char *)pw
, len
*2);
439 /* Create NT hashed password. */
443 MD4_Update(&MD4
, pw
, 2*len
);
444 MD4_Final(ntbuffer
, &MD4
);
446 memset(ntbuffer
+ 16, 0, 21 - 16);
456 #ifdef USE_WINDOWS_SSPI
459 ntlm_sspi_cleanup(struct ntlmdata
*ntlm
)
465 if (ntlm
->has_handles
) {
466 s_pSecFn
->DeleteSecurityContext(&ntlm
->c_handle
);
467 s_pSecFn
->FreeCredentialsHandle(&ntlm
->handle
);
468 ntlm
->has_handles
= 0;
470 if (ntlm
->p_identity
) {
471 if (ntlm
->identity
.User
) free(ntlm
->identity
.User
);
472 if (ntlm
->identity
.Password
) free(ntlm
->identity
.Password
);
473 if (ntlm
->identity
.Domain
) free(ntlm
->identity
.Domain
);
474 ntlm
->p_identity
= NULL
;
480 #define SHORTPAIR(x) ((x) & 0xff), (((x) >> 8) & 0xff)
481 #define LONGQUARTET(x) ((x) & 0xff), (((x) >> 8)&0xff), \
482 (((x) >>16)&0xff), (((x)>>24) & 0xff)
484 #define HOSTNAME_MAX 1024
486 /* this is for creating ntlm header output */
487 CURLcode
Curl_output_ntlm(struct connectdata
*conn
,
490 const char *domain
=""; /* empty */
491 char host
[HOSTNAME_MAX
+ 1] = ""; /* empty */
492 #ifndef USE_WINDOWS_SSPI
493 size_t domlen
= strlen(domain
);
494 size_t hostlen
= strlen(host
);
495 size_t hostoff
; /* host name offset */
496 size_t domoff
; /* domain name offset */
500 unsigned char ntlmbuf
[1024]; /* enough, unless the user+host+domain is very
503 /* point to the address of the pointer that holds the string to sent to the
504 server, which is for a plain host or for a HTTP proxy */
507 /* point to the name and password for this */
510 /* point to the correct struct with this */
511 struct ntlmdata
*ntlm
;
515 curlassert(conn
->data
);
518 allocuserpwd
= &conn
->allocptr
.proxyuserpwd
;
519 userp
= conn
->proxyuser
;
520 passwdp
= conn
->proxypasswd
;
521 ntlm
= &conn
->proxyntlm
;
522 authp
= &conn
->data
->state
.authproxy
;
525 allocuserpwd
= &conn
->allocptr
.userpwd
;
527 passwdp
= conn
->passwd
;
529 authp
= &conn
->data
->state
.authhost
;
533 /* not set means empty */
540 #ifdef USE_WINDOWS_SSPI
541 /* If security interface is not yet initialized try to do this */
542 if (s_hSecDll
== NULL
) {
543 /* Determine Windows version. Security functions are located in
544 * security.dll on WinNT 4.0 and in secur32.dll on Win9x. Win2K and XP
545 * contain both these DLLs (security.dll just forwards calls to
549 osver
.dwOSVersionInfoSize
= sizeof(osver
);
550 GetVersionEx(&osver
);
551 if (osver
.dwPlatformId
== VER_PLATFORM_WIN32_NT
552 && osver
.dwMajorVersion
== 4)
553 s_hSecDll
= LoadLibrary("security.dll");
555 s_hSecDll
= LoadLibrary("secur32.dll");
556 if (s_hSecDll
!= NULL
) {
557 INIT_SECURITY_INTERFACE pInitSecurityInterface
;
558 pInitSecurityInterface
=
559 (INIT_SECURITY_INTERFACE
)GetProcAddress(s_hSecDll
,
560 "InitSecurityInterfaceA");
561 if (pInitSecurityInterface
!= NULL
)
562 s_pSecFn
= pInitSecurityInterface();
565 if (s_pSecFn
== NULL
)
566 return CURLE_RECV_ERROR
;
569 switch(ntlm
->state
) {
570 case NTLMSTATE_TYPE1
:
571 default: /* for the weird cases we (re)start here */
572 #ifdef USE_WINDOWS_SSPI
576 SECURITY_STATUS status
;
580 TimeStamp tsDummy
; /* For Windows 9x compatibility of SPPI calls */
582 ntlm_sspi_cleanup(ntlm
);
584 user
= strchr(userp
, '\\');
586 user
= strchr(userp
, '/');
590 domlen
= user
- userp
;
600 /* note: initialize all of this before doing the mallocs so that
601 * it can be cleaned up later without leaking memory.
603 ntlm
->p_identity
= &ntlm
->identity
;
604 memset(ntlm
->p_identity
, 0, sizeof(*ntlm
->p_identity
));
605 if ((ntlm
->identity
.User
= (unsigned char *)strdup(user
)) == NULL
)
606 return CURLE_OUT_OF_MEMORY
;
607 ntlm
->identity
.UserLength
= strlen(user
);
608 if ((ntlm
->identity
.Password
= (unsigned char *)strdup(passwdp
)) == NULL
)
609 return CURLE_OUT_OF_MEMORY
;
610 ntlm
->identity
.PasswordLength
= strlen(passwdp
);
611 if ((ntlm
->identity
.Domain
= malloc(domlen
+1)) == NULL
)
612 return CURLE_OUT_OF_MEMORY
;
613 strncpy((char *)ntlm
->identity
.Domain
, domain
, domlen
);
614 ntlm
->identity
.Domain
[domlen
] = '\0';
615 ntlm
->identity
.DomainLength
= domlen
;
616 ntlm
->identity
.Flags
= SEC_WINNT_AUTH_IDENTITY_ANSI
;
619 ntlm
->p_identity
= NULL
;
622 if (s_pSecFn
->AcquireCredentialsHandle(
623 NULL
, (char *)"NTLM", SECPKG_CRED_OUTBOUND
, NULL
, ntlm
->p_identity
,
624 NULL
, NULL
, &ntlm
->handle
, &tsDummy
626 return CURLE_OUT_OF_MEMORY
;
629 desc
.ulVersion
= SECBUFFER_VERSION
;
631 desc
.pBuffers
= &buf
;
632 buf
.cbBuffer
= sizeof(ntlmbuf
);
633 buf
.BufferType
= SECBUFFER_TOKEN
;
634 buf
.pvBuffer
= ntlmbuf
;
636 status
= s_pSecFn
->InitializeSecurityContext(&ntlm
->handle
, NULL
,
638 ISC_REQ_CONFIDENTIALITY
|
639 ISC_REQ_REPLAY_DETECT
|
641 0, SECURITY_NETWORK_DREP
,
643 &ntlm
->c_handle
, &desc
,
646 if (status
== SEC_I_COMPLETE_AND_CONTINUE
||
647 status
== SEC_I_CONTINUE_NEEDED
) {
648 s_pSecFn
->CompleteAuthToken(&ntlm
->c_handle
, &desc
);
650 else if (status
!= SEC_E_OK
) {
651 s_pSecFn
->FreeCredentialsHandle(&ntlm
->handle
);
652 return CURLE_RECV_ERROR
;
655 ntlm
->has_handles
= 1;
660 domoff
= hostoff
+ hostlen
; /* This is 0: remember that host and domain
663 /* Create and send a type-1 message:
665 Index Description Content
666 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
668 8 NTLM Message Type long (0x01000000)
670 16 Supplied Domain security buffer(*)
671 24 Supplied Workstation security buffer(*)
672 32 start of data block
676 #define NTLM2FLAG NTLMFLAG_NEGOTIATE_NTLM2_KEY
680 snprintf((char *)ntlmbuf
, sizeof(ntlmbuf
), NTLMSSP_SIGNATURE
"%c"
681 "\x01%c%c%c" /* 32-bit type = 1 */
682 "%c%c%c%c" /* 32-bit NTLM flag field */
683 "%c%c" /* domain length */
684 "%c%c" /* domain allocated space */
685 "%c%c" /* domain name offset */
686 "%c%c" /* 2 zeroes */
687 "%c%c" /* host length */
688 "%c%c" /* host allocated space */
689 "%c%c" /* host name offset */
690 "%c%c" /* 2 zeroes */
692 "%s", /* domain string */
693 0, /* trailing zero */
694 0,0,0, /* part of type-1 long */
697 NTLMFLAG_NEGOTIATE_OEM
|
698 NTLMFLAG_REQUEST_TARGET
|
699 NTLMFLAG_NEGOTIATE_NTLM_KEY
|
701 NTLMFLAG_NEGOTIATE_ALWAYS_SIGN
711 host
/* this is empty */, domain
/* this is empty */);
713 /* initial packet length */
714 size
= 32 + hostlen
+ domlen
;
718 fprintf(stderr
, "**** TYPE1 header flags=0x%02.2x%02.2x%02.2x%02.2x 0x%08.8x ",
719 LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM
|
720 NTLMFLAG_REQUEST_TARGET
|
721 NTLMFLAG_NEGOTIATE_NTLM_KEY
|
723 NTLMFLAG_NEGOTIATE_ALWAYS_SIGN
),
724 NTLMFLAG_NEGOTIATE_OEM
|
725 NTLMFLAG_REQUEST_TARGET
|
726 NTLMFLAG_NEGOTIATE_NTLM_KEY
|
728 NTLMFLAG_NEGOTIATE_ALWAYS_SIGN
);
730 NTLMFLAG_NEGOTIATE_OEM
|
731 NTLMFLAG_REQUEST_TARGET
|
732 NTLMFLAG_NEGOTIATE_NTLM_KEY
|
734 NTLMFLAG_NEGOTIATE_ALWAYS_SIGN
);
735 fprintf(stderr
, "\n****\n");
738 /* now size is the size of the base64 encoded package size */
739 size
= Curl_base64_encode(NULL
, (char *)ntlmbuf
, size
, &base64
);
742 Curl_safefree(*allocuserpwd
);
743 *allocuserpwd
= aprintf("%sAuthorization: NTLM %s\r\n",
746 DEBUG_OUT(fprintf(stderr
, "**** Header %s\n ", *allocuserpwd
));
750 return CURLE_OUT_OF_MEMORY
; /* FIX TODO */
754 case NTLMSTATE_TYPE2
:
755 /* We received the type-2 message already, create a type-3 message:
757 Index Description Content
758 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
760 8 NTLM Message Type long (0x03000000)
761 12 LM/LMv2 Response security buffer(*)
762 20 NTLM/NTLMv2 Response security buffer(*)
763 28 Domain Name security buffer(*)
764 36 User Name security buffer(*)
765 44 Workstation Name security buffer(*)
766 (52) Session Key (optional) security buffer(*)
767 (60) Flags (optional) long
768 52 (64) start of data block
773 #ifdef USE_WINDOWS_SSPI
774 SecBuffer type_2
, type_3
;
775 SecBufferDesc type_2_desc
, type_3_desc
;
776 SECURITY_STATUS status
;
778 TimeStamp tsDummy
; /* For Windows 9x compatibility of SPPI calls */
780 type_2_desc
.ulVersion
= type_3_desc
.ulVersion
= SECBUFFER_VERSION
;
781 type_2_desc
.cBuffers
= type_3_desc
.cBuffers
= 1;
782 type_2_desc
.pBuffers
= &type_2
;
783 type_3_desc
.pBuffers
= &type_3
;
785 type_2
.BufferType
= SECBUFFER_TOKEN
;
786 type_2
.pvBuffer
= ntlm
->type_2
;
787 type_2
.cbBuffer
= ntlm
->n_type_2
;
788 type_3
.BufferType
= SECBUFFER_TOKEN
;
789 type_3
.pvBuffer
= ntlmbuf
;
790 type_3
.cbBuffer
= sizeof(ntlmbuf
);
792 status
= s_pSecFn
->InitializeSecurityContext(&ntlm
->handle
, &ntlm
->c_handle
,
794 ISC_REQ_CONFIDENTIALITY
|
795 ISC_REQ_REPLAY_DETECT
|
797 0, SECURITY_NETWORK_DREP
, &type_2_desc
,
798 0, &ntlm
->c_handle
, &type_3_desc
,
801 if (status
!= SEC_E_OK
)
802 return CURLE_RECV_ERROR
;
804 size
= type_3
.cbBuffer
;
806 ntlm_sspi_cleanup(ntlm
);
810 unsigned char lmresp
[24]; /* fixed-size */
813 unsigned char ntresp
[24]; /* fixed-size */
819 user
= strchr(userp
, '\\');
821 user
= strchr(userp
, '/');
825 domlen
= (user
- domain
);
830 userlen
= strlen(user
);
832 if (gethostname(host
, HOSTNAME_MAX
)) {
833 infof(conn
->data
, "gethostname() failed, continuing without!");
837 /* If the workstation if configured with a full DNS name (i.e.
838 * workstation.somewhere.net) gethostname() returns the fully qualified
839 * name, which NTLM doesn't like.
841 char *dot
= strchr(host
, '.');
844 hostlen
= strlen(host
);
848 /* We don't support NTLM2 if we don't have USE_NTRESPONSES */
849 if (ntlm
->flags
& NTLMFLAG_NEGOTIATE_NTLM2_KEY
) {
850 unsigned char ntbuffer
[0x18];
851 unsigned char tmp
[0x18];
852 unsigned char md5sum
[MD5_DIGEST_LENGTH
];
854 unsigned char random
[8];
856 /* Need to create 8 bytes random data */
857 Curl_ossl_seed(conn
->data
); /* Initiate the seed if not already done */
858 RAND_bytes(random
,8);
860 /* 8 bytes random data as challenge in lmresp */
861 memcpy(lmresp
,random
,8);
863 memset(lmresp
+8,0,0x10);
865 /* Fill tmp with challenge(nonce?) + random */
866 memcpy(tmp
,&ntlm
->nonce
[0],8);
867 memcpy(tmp
+8,random
,8);
870 MD5_Update(&MD5
, tmp
, 16);
871 MD5_Final(md5sum
, &MD5
);
872 /* We shall only use the first 8 bytes of md5sum,
873 but the des code in lm_resp only encrypt the first 8 bytes */
874 mk_nt_hash(conn
->data
, passwdp
, ntbuffer
);
875 lm_resp(ntbuffer
, md5sum
, ntresp
);
877 /* End of NTLM2 Session code */
883 unsigned char ntbuffer
[0x18];
885 unsigned char lmbuffer
[0x18];
888 mk_nt_hash(conn
->data
, passwdp
, ntbuffer
);
889 lm_resp(ntbuffer
, &ntlm
->nonce
[0], ntresp
);
892 mk_lm_hash(conn
->data
, passwdp
, lmbuffer
);
893 lm_resp(lmbuffer
, &ntlm
->nonce
[0], lmresp
);
894 /* A safer but less compatible alternative is:
895 * lm_resp(ntbuffer, &ntlm->nonce[0], lmresp);
896 * See http://davenport.sourceforge.net/ntlm.html#ntlmVersion2 */
901 lmrespoff
= 64; /* size of the message header */
903 ntrespoff
= lmrespoff
+ 0x18;
904 domoff
= ntrespoff
+ 0x18;
906 domoff
= lmrespoff
+ 0x18;
908 useroff
= domoff
+ domlen
;
909 hostoff
= useroff
+ userlen
;
911 /* Create the big type-3 message binary blob */
912 size
= snprintf((char *)ntlmbuf
, sizeof(ntlmbuf
),
913 NTLMSSP_SIGNATURE
"%c"
914 "\x03%c%c%c" /* type-3, 32 bits */
916 "%c%c" /* LanManager length */
917 "%c%c" /* LanManager allocated space */
918 "%c%c" /* LanManager offset */
919 "%c%c" /* 2 zeroes */
921 "%c%c" /* NT-response length */
922 "%c%c" /* NT-response allocated space */
923 "%c%c" /* NT-response offset */
924 "%c%c" /* 2 zeroes */
926 "%c%c" /* domain length */
927 "%c%c" /* domain allocated space */
928 "%c%c" /* domain name offset */
929 "%c%c" /* 2 zeroes */
931 "%c%c" /* user length */
932 "%c%c" /* user allocated space */
933 "%c%c" /* user offset */
934 "%c%c" /* 2 zeroes */
936 "%c%c" /* host length */
937 "%c%c" /* host allocated space */
938 "%c%c" /* host offset */
939 "%c%c" /* 2 zeroes */
941 "%c%c" /* session key length (unknown purpose) */
942 "%c%c" /* session key allocated space (unknown purpose) */
943 "%c%c" /* session key offset (unknown purpose) */
944 "%c%c" /* 2 zeroes */
946 "%c%c%c%c" /* flags */
951 /* LanManager response */
954 0, /* zero termination */
955 0,0,0, /* type-3 long, the 24 upper bits */
957 SHORTPAIR(0x18), /* LanManager response length, twice */
959 SHORTPAIR(lmrespoff
),
963 SHORTPAIR(0x18), /* NT-response length, twice */
965 SHORTPAIR(ntrespoff
),
993 LONGQUARTET(ntlm
->flags
));
994 DEBUG_OUT(assert(size
==64));
996 DEBUG_OUT(assert(size
== lmrespoff
));
997 /* We append the binary hashes */
998 if(size
< (sizeof(ntlmbuf
) - 0x18)) {
999 memcpy(&ntlmbuf
[size
], lmresp
, 0x18);
1004 fprintf(stderr
, "**** TYPE3 header lmresp=");
1005 print_hex(stderr
, (char *)&ntlmbuf
[lmrespoff
], 0x18);
1009 if(size
< (sizeof(ntlmbuf
) - 0x18)) {
1010 DEBUG_OUT(assert(size
== ntrespoff
));
1011 memcpy(&ntlmbuf
[size
], ntresp
, 0x18);
1016 fprintf(stderr
, "\n ntresp=");
1017 print_hex(stderr
, (char *)&ntlmbuf
[ntrespoff
], 0x18);
1023 fprintf(stderr
, "\n flags=0x%02.2x%02.2x%02.2x%02.2x 0x%08.8x ",
1024 LONGQUARTET(ntlm
->flags
), ntlm
->flags
);
1025 print_flags(stderr
, ntlm
->flags
);
1026 fprintf(stderr
, "\n****\n");
1030 /* Make sure that the domain, user and host strings fit in the target
1031 buffer before we copy them there. */
1032 if(size
+ userlen
+ domlen
+ hostlen
>= sizeof(ntlmbuf
)) {
1033 failf(conn
->data
, "user + domain + host name too big");
1034 return CURLE_OUT_OF_MEMORY
;
1037 curlassert(size
== domoff
);
1038 memcpy(&ntlmbuf
[size
], domain
, domlen
);
1041 curlassert(size
== useroff
);
1042 memcpy(&ntlmbuf
[size
], user
, userlen
);
1045 curlassert(size
== hostoff
);
1046 memcpy(&ntlmbuf
[size
], host
, hostlen
);
1049 #ifdef CURL_DOES_CONVERSIONS
1050 /* convert domain, user, and host to ASCII but leave the rest as-is */
1051 if(CURLE_OK
!= Curl_convert_to_network(conn
->data
,
1052 (char *)&ntlmbuf
[domoff
],
1054 return CURLE_CONV_FAILED
;
1056 #endif /* CURL_DOES_CONVERSIONS */
1060 /* convert the binary blob into base64 */
1061 size
= Curl_base64_encode(NULL
, (char *)ntlmbuf
, size
, &base64
);
1064 Curl_safefree(*allocuserpwd
);
1065 *allocuserpwd
= aprintf("%sAuthorization: NTLM %s\r\n",
1068 DEBUG_OUT(fprintf(stderr
, "**** %s\n ", *allocuserpwd
));
1072 return CURLE_OUT_OF_MEMORY
; /* FIX TODO */
1074 ntlm
->state
= NTLMSTATE_TYPE3
; /* we sent a type-3 */
1079 case NTLMSTATE_TYPE3
:
1080 /* connection is already authenticated,
1081 * don't send a header in future requests */
1083 free(*allocuserpwd
);
1095 Curl_ntlm_cleanup(struct connectdata
*conn
)
1097 #ifdef USE_WINDOWS_SSPI
1098 ntlm_sspi_cleanup(&conn
->ntlm
);
1099 ntlm_sspi_cleanup(&conn
->proxyntlm
);
1100 if (s_hSecDll
!= NULL
) {
1101 FreeLibrary(s_hSecDll
);
1110 #endif /* USE_NTLM */
1111 #endif /* !CURL_DISABLE_HTTP */