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.
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 */
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
73 #include <openssl/des.h>
74 #include <openssl/md4.h>
75 #include <openssl/md5.h>
76 #include <openssl/ssl.h>
77 #include <openssl/rand.h>
79 #if OPENSSL_VERSION_NUMBER < 0x00907001L
80 #define DES_key_schedule des_key_schedule
81 #define DES_cblock des_cblock
82 #define DES_set_odd_parity des_set_odd_parity
83 #define DES_set_key des_set_key
84 #define DES_ecb_encrypt des_ecb_encrypt
86 /* This is how things were done in the old days */
88 #define DESKEYARG(x) x
91 #define DESKEYARG(x) *x
99 /* Handle of security.dll or secur32.dll, depending on Windows version */
100 static HMODULE s_hSecDll = NULL;
101 /* Pointer to SSPI dispatch table */
102 static PSecurityFunctionTable s_pSecFn = NULL;
106 /* The last #include file should be: */
107 #include "memdebug.h"
109 /* Define this to make the type-3 message include the NT response message */
110 #define USE_NTRESPONSES 1
112 /* Define this to make the type-3 message include the NTLM2Session response
113 message, requires USE_NTRESPONSES. */
114 #define USE_NTLM2SESSION 1
116 #ifndef USE_WINDOWS_SSPI
117 /* this function converts from the little endian format used in the incoming
118 package to whatever endian format we're using natively */
119 static unsigned int readint_le(unsigned char *buf) /* must point to a
122 return ((unsigned int)buf[0]) | ((unsigned int)buf[1] << 8) |
123 ((unsigned int)buf[2] << 16) | ((unsigned int)buf[3] << 24);
128 # define DEBUG_OUT(x) x
129 static void print_flags(FILE *handle, unsigned long flags)
131 if(flags & NTLMFLAG_NEGOTIATE_UNICODE)
132 fprintf(handle, "NTLMFLAG_NEGOTIATE_UNICODE ");
133 if(flags & NTLMFLAG_NEGOTIATE_OEM)
134 fprintf(handle, "NTLMFLAG_NEGOTIATE_OEM ");
135 if(flags & NTLMFLAG_REQUEST_TARGET)
136 fprintf(handle, "NTLMFLAG_REQUEST_TARGET ");
138 fprintf(handle, "NTLMFLAG_UNKNOWN_3 ");
139 if(flags & NTLMFLAG_NEGOTIATE_SIGN)
140 fprintf(handle, "NTLMFLAG_NEGOTIATE_SIGN ");
141 if(flags & NTLMFLAG_NEGOTIATE_SEAL)
142 fprintf(handle, "NTLMFLAG_NEGOTIATE_SEAL ");
143 if(flags & NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE)
144 fprintf(handle, "NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE ");
145 if(flags & NTLMFLAG_NEGOTIATE_LM_KEY)
146 fprintf(handle, "NTLMFLAG_NEGOTIATE_LM_KEY ");
147 if(flags & NTLMFLAG_NEGOTIATE_NETWARE)
148 fprintf(handle, "NTLMFLAG_NEGOTIATE_NETWARE ");
149 if(flags & NTLMFLAG_NEGOTIATE_NTLM_KEY)
150 fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM_KEY ");
152 fprintf(handle, "NTLMFLAG_UNKNOWN_10 ");
153 if(flags & NTLMFLAG_NEGOTIATE_ANONYMOUS)
154 fprintf(handle, "NTLMFLAG_NEGOTIATE_ANONYMOUS ");
155 if(flags & NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED)
156 fprintf(handle, "NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED ");
157 if(flags & NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED)
158 fprintf(handle, "NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED ");
159 if(flags & NTLMFLAG_NEGOTIATE_LOCAL_CALL)
160 fprintf(handle, "NTLMFLAG_NEGOTIATE_LOCAL_CALL ");
161 if(flags & NTLMFLAG_NEGOTIATE_ALWAYS_SIGN)
162 fprintf(handle, "NTLMFLAG_NEGOTIATE_ALWAYS_SIGN ");
163 if(flags & NTLMFLAG_TARGET_TYPE_DOMAIN)
164 fprintf(handle, "NTLMFLAG_TARGET_TYPE_DOMAIN ");
165 if(flags & NTLMFLAG_TARGET_TYPE_SERVER)
166 fprintf(handle, "NTLMFLAG_TARGET_TYPE_SERVER ");
167 if(flags & NTLMFLAG_TARGET_TYPE_SHARE)
168 fprintf(handle, "NTLMFLAG_TARGET_TYPE_SHARE ");
169 if(flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY)
170 fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM2_KEY ");
171 if(flags & NTLMFLAG_REQUEST_INIT_RESPONSE)
172 fprintf(handle, "NTLMFLAG_REQUEST_INIT_RESPONSE ");
173 if(flags & NTLMFLAG_REQUEST_ACCEPT_RESPONSE)
174 fprintf(handle, "NTLMFLAG_REQUEST_ACCEPT_RESPONSE ");
175 if(flags & NTLMFLAG_REQUEST_NONNT_SESSION_KEY)
176 fprintf(handle, "NTLMFLAG_REQUEST_NONNT_SESSION_KEY ");
177 if(flags & NTLMFLAG_NEGOTIATE_TARGET_INFO)
178 fprintf(handle, "NTLMFLAG_NEGOTIATE_TARGET_INFO ");
180 fprintf(handle, "NTLMFLAG_UNKNOWN_24 ");
182 fprintf(handle, "NTLMFLAG_UNKNOWN_25 ");
184 fprintf(handle, "NTLMFLAG_UNKNOWN_26 ");
186 fprintf(handle, "NTLMFLAG_UNKNOWN_27 ");
188 fprintf(handle, "NTLMFLAG_UNKNOWN_28 ");
189 if(flags & NTLMFLAG_NEGOTIATE_128)
190 fprintf(handle, "NTLMFLAG_NEGOTIATE_128 ");
191 if(flags & NTLMFLAG_NEGOTIATE_KEY_EXCHANGE)
192 fprintf(handle, "NTLMFLAG_NEGOTIATE_KEY_EXCHANGE ");
193 if(flags & NTLMFLAG_NEGOTIATE_56)
194 fprintf(handle, "NTLMFLAG_NEGOTIATE_56 ");
197 static void print_hex(FILE *handle, const char *buf, size_t len)
200 fprintf(stderr, "0x");
202 fprintf(stderr, "%02.2x", (unsigned int)*p++);
205 # define DEBUG_OUT(x)
209 (*) = A "security buffer" is a triplet consisting of two shorts and one
212 1. a 'short' containing the length of the buffer in bytes
213 2. a 'short' containing the allocated space for the buffer in bytes
214 3. a 'long' containing the offset to the start of the buffer from the
215 beginning of the NTLM message, in bytes.
219 CURLntlm Curl_input_ntlm(struct connectdata *conn,
220 bool proxy, /* if proxy or not */
221 const char *header) /* rest of the www-authenticate:
224 /* point to the correct struct with this */
225 struct ntlmdata *ntlm;
226 #ifndef USE_WINDOWS_SSPI
227 static const char type2_marker[] = { 0x02, 0x00, 0x00, 0x00 };
230 ntlm = proxy?&conn->proxyntlm:&conn->ntlm;
232 /* skip initial whitespaces */
233 while(*header && ISSPACE(*header))
236 if(checkprefix("NTLM", header)) {
237 header += strlen("NTLM");
239 while(*header && ISSPACE(*header))
243 /* We got a type-2 message here:
245 Index Description Content
246 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
248 8 NTLM Message Type long (0x02000000)
249 12 Target Name security buffer(*)
252 (32) Context (optional) 8 bytes (two consecutive longs)
253 (40) Target Information (optional) security buffer(*)
254 32 (48) start of data block
257 unsigned char *buffer;
258 size = Curl_base64_decode(header, &buffer);
262 ntlm->state = NTLMSTATE_TYPE2; /* we got a type-2 */
264 #ifdef USE_WINDOWS_SSPI
265 ntlm->type_2 = malloc(size+1);
266 if(ntlm->type_2 == NULL) {
268 return CURLE_OUT_OF_MEMORY;
270 ntlm->n_type_2 = size;
271 memcpy(ntlm->type_2, buffer, size);
276 (memcmp(buffer, NTLMSSP_SIGNATURE, 8) != 0) ||
277 (memcmp(buffer+8, type2_marker, sizeof(type2_marker)) != 0)) {
278 /* This was not a good enough type-2 message */
283 ntlm->flags = readint_le(&buffer[20]);
284 memcpy(ntlm->nonce, &buffer[24], 8);
287 fprintf(stderr, "**** TYPE2 header flags=0x%08.8lx ", ntlm->flags);
288 print_flags(stderr, ntlm->flags);
289 fprintf(stderr, "\n nonce=");
290 print_hex(stderr, (char *)ntlm->nonce, 8);
291 fprintf(stderr, "\n****\n");
292 fprintf(stderr, "**** Header %s\n ", header);
299 if(ntlm->state >= NTLMSTATE_TYPE1)
302 ntlm->state = NTLMSTATE_TYPE1; /* we should sent away a type-1 */
305 return CURLNTLM_FINE;
308 #ifndef USE_WINDOWS_SSPI
311 * Turns a 56 bit key into the 64 bit, odd parity key and sets the key. The
312 * key schedule ks is also set.
314 static void setup_des_key(unsigned char *key_56,
315 DES_key_schedule DESKEYARG(ks))
320 key[1] = (unsigned char)(((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1));
321 key[2] = (unsigned char)(((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2));
322 key[3] = (unsigned char)(((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3));
323 key[4] = (unsigned char)(((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4));
324 key[5] = (unsigned char)(((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5));
325 key[6] = (unsigned char)(((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6));
326 key[7] = (unsigned char) ((key_56[6] << 1) & 0xFF);
328 DES_set_odd_parity(&key);
329 DES_set_key(&key, ks);
333 * takes a 21 byte array and treats it as 3 56-bit DES keys. The
334 * 8 byte plaintext is encrypted with each key and the resulting 24
335 * bytes are stored in the results array.
337 static void lm_resp(unsigned char *keys,
338 unsigned char *plaintext,
339 unsigned char *results)
343 setup_des_key(keys, DESKEY(ks));
344 DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) results,
345 DESKEY(ks), DES_ENCRYPT);
347 setup_des_key(keys+7, DESKEY(ks));
348 DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results+8),
349 DESKEY(ks), DES_ENCRYPT);
351 setup_des_key(keys+14, DESKEY(ks));
352 DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results+16),
353 DESKEY(ks), DES_ENCRYPT);
358 * Set up lanmanager hashed password
360 static void mk_lm_hash(struct SessionHandle *data,
362 unsigned char *lmbuffer /* 21 bytes */)
364 unsigned char pw[14];
365 static const unsigned char magic[] = {
366 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 /* i.e. KGS!@#$% */
369 size_t len = strlen(password);
374 for (i=0; i<len; i++)
375 pw[i] = (unsigned char)toupper(password[i]);
380 #ifdef CURL_DOES_CONVERSIONS
382 * The LanManager hashed password needs to be created using the
383 * password in the network encoding not the host encoding.
386 Curl_convert_to_network(data, (char *)pw, 14);
392 /* Create LanManager hashed password. */
396 setup_des_key(pw, DESKEY(ks));
397 DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)lmbuffer,
398 DESKEY(ks), DES_ENCRYPT);
400 setup_des_key(pw+7, DESKEY(ks));
401 DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)(lmbuffer+8),
402 DESKEY(ks), DES_ENCRYPT);
404 memset(lmbuffer + 16, 0, 21 - 16);
409 static void utf8_to_unicode_le(unsigned char *dest, const char *src,
413 for (i=0; i<srclen; i++) {
414 dest[2*i] = (unsigned char)src[i];
420 * Set up nt hashed passwords
422 static CURLcode mk_nt_hash(struct SessionHandle *data,
424 unsigned char *ntbuffer /* 21 bytes */)
426 size_t len = strlen(password);
427 unsigned char *pw = malloc(len*2);
429 return CURLE_OUT_OF_MEMORY;
431 utf8_to_unicode_le(pw, password, len);
433 #ifdef CURL_DOES_CONVERSIONS
435 * The NT hashed password needs to be created using the
436 * password in the network encoding not the host encoding.
439 Curl_convert_to_network(data, (char *)pw, len*2);
445 /* Create NT hashed password. */
449 MD4_Update(&MD4pw, pw, 2*len);
450 MD4_Final(ntbuffer, &MD4pw);
452 memset(ntbuffer + 16, 0, 21 - 16);
463 #ifdef USE_WINDOWS_SSPI
466 ntlm_sspi_cleanup(struct ntlmdata *ntlm)
472 if(ntlm->has_handles) {
473 s_pSecFn->DeleteSecurityContext(&ntlm->c_handle);
474 s_pSecFn->FreeCredentialsHandle(&ntlm->handle);
475 ntlm->has_handles = 0;
477 if(ntlm->p_identity) {
478 if(ntlm->identity.User) free(ntlm->identity.User);
479 if(ntlm->identity.Password) free(ntlm->identity.Password);
480 if(ntlm->identity.Domain) free(ntlm->identity.Domain);
481 ntlm->p_identity = NULL;
487 #define SHORTPAIR(x) ((x) & 0xff), (((x) >> 8) & 0xff)
488 #define LONGQUARTET(x) ((x) & 0xff), (((x) >> 8)&0xff), \
489 (((x) >>16)&0xff), (((x)>>24) & 0xff)
491 #define HOSTNAME_MAX 1024
493 /* this is for creating ntlm header output */
494 CURLcode Curl_output_ntlm(struct connectdata *conn,
497 const char *domain=""; /* empty */
498 char host [HOSTNAME_MAX+ 1] = ""; /* empty */
499 #ifndef USE_WINDOWS_SSPI
500 size_t domlen = strlen(domain);
501 size_t hostlen = strlen(host);
502 size_t hostoff; /* host name offset */
503 size_t domoff; /* domain name offset */
507 unsigned char ntlmbuf[1024]; /* enough, unless the user+host+domain is very
510 /* point to the address of the pointer that holds the string to sent to the
511 server, which is for a plain host or for a HTTP proxy */
514 /* point to the name and password for this */
517 /* point to the correct struct with this */
518 struct ntlmdata *ntlm;
522 DEBUGASSERT(conn->data);
525 allocuserpwd = &conn->allocptr.proxyuserpwd;
526 userp = conn->proxyuser;
527 passwdp = conn->proxypasswd;
528 ntlm = &conn->proxyntlm;
529 authp = &conn->data->state.authproxy;
532 allocuserpwd = &conn->allocptr.userpwd;
534 passwdp = conn->passwd;
536 authp = &conn->data->state.authhost;
540 /* not set means empty */
547 #ifdef USE_WINDOWS_SSPI
548 if (s_hSecDll == NULL) {
549 /* not thread safe and leaks - use curl_global_init() to avoid */
550 CURLcode err = Curl_ntlm_global_init();
551 if (s_hSecDll == NULL)
556 switch(ntlm->state) {
557 case NTLMSTATE_TYPE1:
558 default: /* for the weird cases we (re)start here */
559 #ifdef USE_WINDOWS_SSPI
563 SECURITY_STATUS status;
567 TimeStamp tsDummy; /* For Windows 9x compatibility of SPPI calls */
569 ntlm_sspi_cleanup(ntlm);
571 user = strchr(userp, '\\');
573 user = strchr(userp, '/');
577 domlen = user - userp;
587 /* note: initialize all of this before doing the mallocs so that
588 * it can be cleaned up later without leaking memory.
590 ntlm->p_identity = &ntlm->identity;
591 memset(ntlm->p_identity, 0, sizeof(*ntlm->p_identity));
592 if((ntlm->identity.User = (unsigned char *)strdup(user)) == NULL)
593 return CURLE_OUT_OF_MEMORY;
594 ntlm->identity.UserLength = strlen(user);
595 if((ntlm->identity.Password = (unsigned char *)strdup(passwdp)) == NULL)
596 return CURLE_OUT_OF_MEMORY;
597 ntlm->identity.PasswordLength = strlen(passwdp);
598 if((ntlm->identity.Domain = malloc(domlen+1)) == NULL)
599 return CURLE_OUT_OF_MEMORY;
600 strncpy((char *)ntlm->identity.Domain, domain, domlen);
601 ntlm->identity.Domain[domlen] = '\0';
602 ntlm->identity.DomainLength = domlen;
603 ntlm->identity.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
606 ntlm->p_identity = NULL;
609 if(s_pSecFn->AcquireCredentialsHandle(
610 NULL, (char *)"NTLM", SECPKG_CRED_OUTBOUND, NULL, ntlm->p_identity,
611 NULL, NULL, &ntlm->handle, &tsDummy
613 return CURLE_OUT_OF_MEMORY;
616 desc.ulVersion = SECBUFFER_VERSION;
618 desc.pBuffers = &buf;
619 buf.cbBuffer = sizeof(ntlmbuf);
620 buf.BufferType = SECBUFFER_TOKEN;
621 buf.pvBuffer = ntlmbuf;
623 status = s_pSecFn->InitializeSecurityContext(&ntlm->handle, NULL,
625 ISC_REQ_CONFIDENTIALITY |
626 ISC_REQ_REPLAY_DETECT |
628 0, SECURITY_NETWORK_DREP,
630 &ntlm->c_handle, &desc,
633 if(status == SEC_I_COMPLETE_AND_CONTINUE ||
634 status == SEC_I_CONTINUE_NEEDED) {
635 s_pSecFn->CompleteAuthToken(&ntlm->c_handle, &desc);
637 else if(status != SEC_E_OK) {
638 s_pSecFn->FreeCredentialsHandle(&ntlm->handle);
639 return CURLE_RECV_ERROR;
642 ntlm->has_handles = 1;
647 domoff = hostoff + hostlen; /* This is 0: remember that host and domain
650 /* Create and send a type-1 message:
652 Index Description Content
653 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
655 8 NTLM Message Type long (0x01000000)
657 16 Supplied Domain security buffer(*)
658 24 Supplied Workstation security buffer(*)
659 32 start of data block
663 #define NTLM2FLAG NTLMFLAG_NEGOTIATE_NTLM2_KEY
667 snprintf((char *)ntlmbuf, sizeof(ntlmbuf), NTLMSSP_SIGNATURE "%c"
668 "\x01%c%c%c" /* 32-bit type = 1 */
669 "%c%c%c%c" /* 32-bit NTLM flag field */
670 "%c%c" /* domain length */
671 "%c%c" /* domain allocated space */
672 "%c%c" /* domain name offset */
673 "%c%c" /* 2 zeroes */
674 "%c%c" /* host length */
675 "%c%c" /* host allocated space */
676 "%c%c" /* host name offset */
677 "%c%c" /* 2 zeroes */
679 "%s", /* domain string */
680 0, /* trailing zero */
681 0,0,0, /* part of type-1 long */
684 NTLMFLAG_NEGOTIATE_OEM|
685 NTLMFLAG_REQUEST_TARGET|
686 NTLMFLAG_NEGOTIATE_NTLM_KEY|
688 NTLMFLAG_NEGOTIATE_ALWAYS_SIGN
698 host /* this is empty */, domain /* this is empty */);
700 /* initial packet length */
701 size = 32 + hostlen + domlen;
705 fprintf(stderr, "**** TYPE1 header flags=0x%02.2x%02.2x%02.2x%02.2x 0x%08.8x ",
706 LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM|
707 NTLMFLAG_REQUEST_TARGET|
708 NTLMFLAG_NEGOTIATE_NTLM_KEY|
710 NTLMFLAG_NEGOTIATE_ALWAYS_SIGN),
711 NTLMFLAG_NEGOTIATE_OEM|
712 NTLMFLAG_REQUEST_TARGET|
713 NTLMFLAG_NEGOTIATE_NTLM_KEY|
715 NTLMFLAG_NEGOTIATE_ALWAYS_SIGN);
717 NTLMFLAG_NEGOTIATE_OEM|
718 NTLMFLAG_REQUEST_TARGET|
719 NTLMFLAG_NEGOTIATE_NTLM_KEY|
721 NTLMFLAG_NEGOTIATE_ALWAYS_SIGN);
722 fprintf(stderr, "\n****\n");
725 /* now size is the size of the base64 encoded package size */
726 size = Curl_base64_encode(NULL, (char *)ntlmbuf, size, &base64);
729 Curl_safefree(*allocuserpwd);
730 *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
733 DEBUG_OUT(fprintf(stderr, "**** Header %s\n ", *allocuserpwd));
737 return CURLE_OUT_OF_MEMORY; /* FIX TODO */
741 case NTLMSTATE_TYPE2:
742 /* We received the type-2 message already, create a type-3 message:
744 Index Description Content
745 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
747 8 NTLM Message Type long (0x03000000)
748 12 LM/LMv2 Response security buffer(*)
749 20 NTLM/NTLMv2 Response security buffer(*)
750 28 Domain Name security buffer(*)
751 36 User Name security buffer(*)
752 44 Workstation Name security buffer(*)
753 (52) Session Key (optional) security buffer(*)
754 (60) Flags (optional) long
755 52 (64) start of data block
760 #ifdef USE_WINDOWS_SSPI
761 SecBuffer type_2, type_3;
762 SecBufferDesc type_2_desc, type_3_desc;
763 SECURITY_STATUS status;
765 TimeStamp tsDummy; /* For Windows 9x compatibility of SPPI calls */
767 type_2_desc.ulVersion = type_3_desc.ulVersion = SECBUFFER_VERSION;
768 type_2_desc.cBuffers = type_3_desc.cBuffers = 1;
769 type_2_desc.pBuffers = &type_2;
770 type_3_desc.pBuffers = &type_3;
772 type_2.BufferType = SECBUFFER_TOKEN;
773 type_2.pvBuffer = ntlm->type_2;
774 type_2.cbBuffer = ntlm->n_type_2;
775 type_3.BufferType = SECBUFFER_TOKEN;
776 type_3.pvBuffer = ntlmbuf;
777 type_3.cbBuffer = sizeof(ntlmbuf);
779 status = s_pSecFn->InitializeSecurityContext(&ntlm->handle, &ntlm->c_handle,
781 ISC_REQ_CONFIDENTIALITY |
782 ISC_REQ_REPLAY_DETECT |
784 0, SECURITY_NETWORK_DREP, &type_2_desc,
785 0, &ntlm->c_handle, &type_3_desc,
788 if(status != SEC_E_OK)
789 return CURLE_RECV_ERROR;
791 size = type_3.cbBuffer;
793 ntlm_sspi_cleanup(ntlm);
797 unsigned char lmresp[24]; /* fixed-size */
800 unsigned char ntresp[24]; /* fixed-size */
806 user = strchr(userp, '\\');
808 user = strchr(userp, '/');
812 domlen = (user - domain);
817 userlen = strlen(user);
819 if(gethostname(host, HOSTNAME_MAX)) {
820 infof(conn->data, "gethostname() failed, continuing without!");
824 /* If the workstation if configured with a full DNS name (i.e.
825 * workstation.somewhere.net) gethostname() returns the fully qualified
826 * name, which NTLM doesn't like.
828 char *dot = strchr(host, '.');
831 hostlen = strlen(host);
835 /* We don't support NTLM2 if we don't have USE_NTRESPONSES */
836 if(ntlm->flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) {
837 unsigned char ntbuffer[0x18];
838 unsigned char tmp[0x18];
839 unsigned char md5sum[MD5_DIGEST_LENGTH];
841 unsigned char entropy[8];
843 /* Need to create 8 bytes random data */
844 Curl_ossl_seed(conn->data); /* Initiate the seed if not already done */
845 RAND_bytes(entropy,8);
847 /* 8 bytes random data as challenge in lmresp */
848 memcpy(lmresp,entropy,8);
850 memset(lmresp+8,0,0x10);
852 /* Fill tmp with challenge(nonce?) + entropy */
853 memcpy(tmp,&ntlm->nonce[0],8);
854 memcpy(tmp+8,entropy,8);
857 MD5_Update(&MD5pw, tmp, 16);
858 MD5_Final(md5sum, &MD5pw);
859 /* We shall only use the first 8 bytes of md5sum,
860 but the des code in lm_resp only encrypt the first 8 bytes */
861 if(mk_nt_hash(conn->data, passwdp, ntbuffer) == CURLE_OUT_OF_MEMORY)
862 return CURLE_OUT_OF_MEMORY;
863 lm_resp(ntbuffer, md5sum, ntresp);
865 /* End of NTLM2 Session code */
871 unsigned char ntbuffer[0x18];
873 unsigned char lmbuffer[0x18];
876 if(mk_nt_hash(conn->data, passwdp, ntbuffer) == CURLE_OUT_OF_MEMORY)
877 return CURLE_OUT_OF_MEMORY;
878 lm_resp(ntbuffer, &ntlm->nonce[0], ntresp);
881 mk_lm_hash(conn->data, passwdp, lmbuffer);
882 lm_resp(lmbuffer, &ntlm->nonce[0], lmresp);
883 /* A safer but less compatible alternative is:
884 * lm_resp(ntbuffer, &ntlm->nonce[0], lmresp);
885 * See http://davenport.sourceforge.net/ntlm.html#ntlmVersion2 */
890 lmrespoff = 64; /* size of the message header */
892 ntrespoff = lmrespoff + 0x18;
893 domoff = ntrespoff + 0x18;
895 domoff = lmrespoff + 0x18;
897 useroff = domoff + domlen;
898 hostoff = useroff + userlen;
901 * In the case the server sets the flag NTLMFLAG_NEGOTIATE_UNICODE, we
902 * need to filter it off because libcurl doesn't UNICODE encode the
903 * strings it packs into the NTLM authenticate packet.
905 ntlm->flags &= ~NTLMFLAG_NEGOTIATE_UNICODE;
907 /* Create the big type-3 message binary blob */
908 size = snprintf((char *)ntlmbuf, sizeof(ntlmbuf),
909 NTLMSSP_SIGNATURE "%c"
910 "\x03%c%c%c" /* type-3, 32 bits */
912 "%c%c" /* LanManager length */
913 "%c%c" /* LanManager allocated space */
914 "%c%c" /* LanManager offset */
915 "%c%c" /* 2 zeroes */
917 "%c%c" /* NT-response length */
918 "%c%c" /* NT-response allocated space */
919 "%c%c" /* NT-response offset */
920 "%c%c" /* 2 zeroes */
922 "%c%c" /* domain length */
923 "%c%c" /* domain allocated space */
924 "%c%c" /* domain name offset */
925 "%c%c" /* 2 zeroes */
927 "%c%c" /* user length */
928 "%c%c" /* user allocated space */
929 "%c%c" /* user offset */
930 "%c%c" /* 2 zeroes */
932 "%c%c" /* host length */
933 "%c%c" /* host allocated space */
934 "%c%c" /* host offset */
935 "%c%c" /* 2 zeroes */
937 "%c%c" /* session key length (unknown purpose) */
938 "%c%c" /* session key allocated space (unknown purpose) */
939 "%c%c" /* session key offset (unknown purpose) */
940 "%c%c" /* 2 zeroes */
942 "%c%c%c%c" /* flags */
947 /* LanManager response */
950 0, /* zero termination */
951 0,0,0, /* type-3 long, the 24 upper bits */
953 SHORTPAIR(0x18), /* LanManager response length, twice */
955 SHORTPAIR(lmrespoff),
959 SHORTPAIR(0x18), /* NT-response length, twice */
961 SHORTPAIR(ntrespoff),
989 LONGQUARTET(ntlm->flags));
990 DEBUGASSERT(size==64);
992 DEBUGASSERT(size == (size_t)lmrespoff);
993 /* We append the binary hashes */
994 if(size < (sizeof(ntlmbuf) - 0x18)) {
995 memcpy(&ntlmbuf[size], lmresp, 0x18);
1000 fprintf(stderr, "**** TYPE3 header lmresp=");
1001 print_hex(stderr, (char *)&ntlmbuf[lmrespoff], 0x18);
1005 if(size < (sizeof(ntlmbuf) - 0x18)) {
1006 DEBUGASSERT(size == (size_t)ntrespoff);
1007 memcpy(&ntlmbuf[size], ntresp, 0x18);
1012 fprintf(stderr, "\n ntresp=");
1013 print_hex(stderr, (char *)&ntlmbuf[ntrespoff], 0x18);
1019 fprintf(stderr, "\n flags=0x%02.2x%02.2x%02.2x%02.2x 0x%08.8x ",
1020 LONGQUARTET(ntlm->flags), ntlm->flags);
1021 print_flags(stderr, ntlm->flags);
1022 fprintf(stderr, "\n****\n");
1026 /* Make sure that the domain, user and host strings fit in the target
1027 buffer before we copy them there. */
1028 if(size + userlen + domlen + hostlen >= sizeof(ntlmbuf)) {
1029 failf(conn->data, "user + domain + host name too big");
1030 return CURLE_OUT_OF_MEMORY;
1033 DEBUGASSERT(size == domoff);
1034 memcpy(&ntlmbuf[size], domain, domlen);
1037 DEBUGASSERT(size == useroff);
1038 memcpy(&ntlmbuf[size], user, userlen);
1041 DEBUGASSERT(size == hostoff);
1042 memcpy(&ntlmbuf[size], host, hostlen);
1045 #ifdef CURL_DOES_CONVERSIONS
1046 /* convert domain, user, and host to ASCII but leave the rest as-is */
1047 if(CURLE_OK != Curl_convert_to_network(conn->data,
1048 (char *)&ntlmbuf[domoff],
1050 return CURLE_CONV_FAILED;
1052 #endif /* CURL_DOES_CONVERSIONS */
1056 /* convert the binary blob into base64 */
1057 size = Curl_base64_encode(NULL, (char *)ntlmbuf, size, &base64);
1060 Curl_safefree(*allocuserpwd);
1061 *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
1064 DEBUG_OUT(fprintf(stderr, "**** %s\n ", *allocuserpwd));
1068 return CURLE_OUT_OF_MEMORY; /* FIX TODO */
1070 ntlm->state = NTLMSTATE_TYPE3; /* we sent a type-3 */
1075 case NTLMSTATE_TYPE3:
1076 /* connection is already authenticated,
1077 * don't send a header in future requests */
1079 free(*allocuserpwd);
1091 Curl_ntlm_cleanup(struct connectdata *conn)
1093 #ifdef USE_WINDOWS_SSPI
1094 ntlm_sspi_cleanup(&conn->ntlm);
1095 ntlm_sspi_cleanup(&conn->proxyntlm);
1101 #ifdef USE_WINDOWS_SSPI
1102 CURLcode Curl_ntlm_global_init()
1104 /* If security interface is not yet initialized try to do this */
1105 if(s_hSecDll == NULL) {
1106 /* Determine Windows version. Security functions are located in
1107 * security.dll on WinNT 4.0 and in secur32.dll on Win9x. Win2K and XP
1108 * contain both these DLLs (security.dll just forwards calls to
1111 OSVERSIONINFO osver;
1112 osver.dwOSVersionInfoSize = sizeof(osver);
1113 GetVersionEx(&osver);
1114 if(osver.dwPlatformId == VER_PLATFORM_WIN32_NT
1115 && osver.dwMajorVersion == 4)
1116 s_hSecDll = LoadLibrary("security.dll");
1118 s_hSecDll = LoadLibrary("secur32.dll");
1119 if(s_hSecDll != NULL) {
1120 INIT_SECURITY_INTERFACE pInitSecurityInterface;
1121 pInitSecurityInterface =
1122 (INIT_SECURITY_INTERFACE)GetProcAddress(s_hSecDll,
1123 "InitSecurityInterfaceA");
1124 if(pInitSecurityInterface != NULL)
1125 s_pSecFn = pInitSecurityInterface();
1128 if(s_pSecFn == NULL)
1129 return CURLE_RECV_ERROR;
1134 void Curl_ntlm_global_cleanup()
1136 if(s_hSecDll != NULL) {
1137 FreeLibrary(s_hSecDll);
1144 #endif /* USE_NTLM */
1145 #endif /* !CURL_DISABLE_HTTP */