Resync
[CMakeLuaTailorHgBridge.git] / CMakeLua / Utilities / cmcurl-7.19.0 / lib / http_ntlm.c
blobc370d7da591289a027aaf029ead3f8f53f5ae7f1
1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
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 ***************************************************************************/
23 #include "setup.h"
25 /* NTLM details:
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
36 #ifdef USE_NTLM
38 #define DEBUG_ME 0
40 /* -- WIN32 approved -- */
41 #include <stdio.h>
42 #include <string.h>
43 #include <stdarg.h>
44 #include <stdlib.h>
45 #include <ctype.h>
47 #ifdef HAVE_UNISTD_H
48 #include <unistd.h>
49 #endif
51 #if (defined(NETWARE) && !defined(__NOVELL_LIBC__))
52 #include <netdb.h>
53 #endif
55 #include "urldata.h"
56 #include "easyif.h" /* for Curl_convert_... prototypes */
57 #include "sendf.h"
58 #include "strequal.h"
59 #include "curl_base64.h"
60 #include "http_ntlm.h"
61 #include "url.h"
62 #include "memory.h"
63 #include "ssluse.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 # ifdef USE_SSLEAY
74 # ifdef USE_OPENSSL
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>
80 # else
81 # include <des.h>
82 # include <md4.h>
83 # include <md5.h>
84 # include <ssl.h>
85 # include <rand.h>
86 # endif
87 # else
88 # error "Can't compile NTLM support without OpenSSL."
89 # endif
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 */
99 #define DESKEY(x) x
100 #define DESKEYARG(x) x
101 #else
102 /* Modern version */
103 #define DESKEYARG(x) *x
104 #define DESKEY(x) &x
105 #endif
107 #else
109 #include <rpc.h>
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;
116 #endif
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
132 4 bytes buffer*/
134 return ((unsigned int)buf[0]) | ((unsigned int)buf[1] << 8) |
135 ((unsigned int)buf[2] << 16) | ((unsigned int)buf[3] << 24);
137 #endif
139 #if DEBUG_ME
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 ");
149 if(flags & (1<<3))
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 ");
163 if(flags & (1<<10))
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 ");
191 if(flags & (1<<24))
192 fprintf(handle, "NTLMFLAG_UNKNOWN_24 ");
193 if(flags & (1<<25))
194 fprintf(handle, "NTLMFLAG_UNKNOWN_25 ");
195 if(flags & (1<<26))
196 fprintf(handle, "NTLMFLAG_UNKNOWN_26 ");
197 if(flags & (1<<27))
198 fprintf(handle, "NTLMFLAG_UNKNOWN_27 ");
199 if(flags & (1<<28))
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)
211 const char *p = buf;
212 fprintf(stderr, "0x");
213 while(len-- > 0)
214 fprintf(stderr, "%02.2x", (unsigned int)*p++);
216 #else
217 # define DEBUG_OUT(x)
218 #endif
221 (*) = A "security buffer" is a triplet consisting of two shorts and one
222 long:
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:
234 header */
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 };
240 #endif
242 ntlm = proxy?&conn->proxyntlm:&conn->ntlm;
244 /* skip initial whitespaces */
245 while(*header && ISSPACE(*header))
246 header++;
248 if(checkprefix("NTLM", header)) {
249 header += strlen("NTLM");
251 while(*header && ISSPACE(*header))
252 header++;
254 if(*header) {
255 /* We got a type-2 message here:
257 Index Description Content
258 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
259 (0x4e544c4d53535000)
260 8 NTLM Message Type long (0x02000000)
261 12 Target Name security buffer(*)
262 20 Flags long
263 24 Challenge 8 bytes
264 (32) Context (optional) 8 bytes (two consecutive longs)
265 (40) Target Information (optional) security buffer(*)
266 32 (48) start of data block
268 size_t size;
269 unsigned char *buffer;
270 size = Curl_base64_decode(header, &buffer);
271 if(!buffer)
272 return CURLNTLM_BAD;
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) {
279 free(buffer);
280 return CURLE_OUT_OF_MEMORY;
282 ntlm->n_type_2 = size;
283 memcpy(ntlm->type_2, buffer, size);
284 #else
285 ntlm->flags = 0;
287 if((size < 32) ||
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 */
291 free(buffer);
292 return CURLNTLM_BAD;
295 ntlm->flags = readint_le(&buffer[20]);
296 memcpy(ntlm->nonce, &buffer[24], 8);
298 DEBUG_OUT({
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);
307 free(buffer);
308 #endif
310 else {
311 if(ntlm->state >= NTLMSTATE_TYPE1)
312 return CURLNTLM_BAD;
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))
329 DES_cblock key;
331 key[0] = key_56[0];
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)
353 DES_key_schedule ks;
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,
373 char *password,
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!@#$% */
380 unsigned int i;
381 size_t len = strlen(password);
383 if(len > 14)
384 len = 14;
386 for (i=0; i<len; i++)
387 pw[i] = (unsigned char)toupper(password[i]);
389 for (; i<14; i++)
390 pw[i] = 0;
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.
397 if(data)
398 Curl_convert_to_network(data, (char *)pw, 14);
399 #else
400 (void)data;
401 #endif
404 /* Create LanManager hashed password. */
406 DES_key_schedule ks;
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);
420 #if USE_NTRESPONSES
421 static void utf8_to_unicode_le(unsigned char *dest, const char *src,
422 size_t srclen)
424 size_t i;
425 for (i=0; i<srclen; i++) {
426 dest[2*i] = (unsigned char)src[i];
427 dest[2*i+1] = '\0';
432 * Set up nt hashed passwords
434 static CURLcode mk_nt_hash(struct SessionHandle *data,
435 char *password,
436 unsigned char *ntbuffer /* 21 bytes */)
438 size_t len = strlen(password);
439 unsigned char *pw = malloc(len*2);
440 if(!pw)
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.
450 if(data)
451 Curl_convert_to_network(data, (char *)pw, len*2);
452 #else
453 (void)data;
454 #endif
457 /* Create NT hashed password. */
458 MD4_CTX MD4pw;
460 MD4_Init(&MD4pw);
461 MD4_Update(&MD4pw, pw, 2*len);
462 MD4_Final(ntbuffer, &MD4pw);
464 memset(ntbuffer + 16, 0, 21 - 16);
467 free(pw);
468 return CURLE_OK;
470 #endif
473 #endif
475 #ifdef USE_WINDOWS_SSPI
477 static void
478 ntlm_sspi_cleanup(struct ntlmdata *ntlm)
480 if(ntlm->type_2) {
481 free(ntlm->type_2);
482 ntlm->type_2 = NULL;
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;
497 #endif
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,
507 bool proxy)
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 */
516 #endif
517 size_t size;
518 char *base64=NULL;
519 unsigned char ntlmbuf[1024]; /* enough, unless the user+host+domain is very
520 long */
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 */
524 char **allocuserpwd;
526 /* point to the name and password for this */
527 char *userp;
528 char *passwdp;
529 /* point to the correct struct with this */
530 struct ntlmdata *ntlm;
531 struct auth *authp;
533 DEBUGASSERT(conn);
534 DEBUGASSERT(conn->data);
536 if(proxy) {
537 allocuserpwd = &conn->allocptr.proxyuserpwd;
538 userp = conn->proxyuser;
539 passwdp = conn->proxypasswd;
540 ntlm = &conn->proxyntlm;
541 authp = &conn->data->state.authproxy;
543 else {
544 allocuserpwd = &conn->allocptr.userpwd;
545 userp = conn->user;
546 passwdp = conn->passwd;
547 ntlm = &conn->ntlm;
548 authp = &conn->data->state.authhost;
550 authp->done = FALSE;
552 /* not set means empty */
553 if(!userp)
554 userp=(char *)"";
556 if(!passwdp)
557 passwdp=(char *)"";
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)
564 return err;
566 #endif
568 switch(ntlm->state) {
569 case NTLMSTATE_TYPE1:
570 default: /* for the weird cases we (re)start here */
571 #ifdef USE_WINDOWS_SSPI
573 SecBuffer buf;
574 SecBufferDesc desc;
575 SECURITY_STATUS status;
576 ULONG attrs;
577 const char *user;
578 int domlen;
579 TimeStamp tsDummy; /* For Windows 9x compatibility of SPPI calls */
581 ntlm_sspi_cleanup(ntlm);
583 user = strchr(userp, '\\');
584 if(!user)
585 user = strchr(userp, '/');
587 if(user) {
588 domain = userp;
589 domlen = user - userp;
590 user++;
592 else {
593 user = userp;
594 domain = "";
595 domlen = 0;
598 if(user && *user) {
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;
617 else {
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
624 ) != SEC_E_OK) {
625 return CURLE_OUT_OF_MEMORY;
628 desc.ulVersion = SECBUFFER_VERSION;
629 desc.cBuffers = 1;
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,
636 (char *) host,
637 ISC_REQ_CONFIDENTIALITY |
638 ISC_REQ_REPLAY_DETECT |
639 ISC_REQ_CONNECTION,
640 0, SECURITY_NETWORK_DREP,
641 NULL, 0,
642 &ntlm->c_handle, &desc,
643 &attrs, &tsDummy);
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;
655 size = buf.cbBuffer;
657 #else
658 hostoff = 0;
659 domoff = hostoff + hostlen; /* This is 0: remember that host and domain
660 are empty */
662 /* Create and send a type-1 message:
664 Index Description Content
665 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
666 (0x4e544c4d53535000)
667 8 NTLM Message Type long (0x01000000)
668 12 Flags long
669 16 Supplied Domain security buffer(*)
670 24 Supplied Workstation security buffer(*)
671 32 start of data block
674 #if USE_NTLM2SESSION
675 #define NTLM2FLAG NTLMFLAG_NEGOTIATE_NTLM2_KEY
676 #else
677 #define NTLM2FLAG 0
678 #endif
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 */
690 "%s" /* host name */
691 "%s", /* domain string */
692 0, /* trailing zero */
693 0,0,0, /* part of type-1 long */
695 LONGQUARTET(
696 NTLMFLAG_NEGOTIATE_OEM|
697 NTLMFLAG_REQUEST_TARGET|
698 NTLMFLAG_NEGOTIATE_NTLM_KEY|
699 NTLM2FLAG|
700 NTLMFLAG_NEGOTIATE_ALWAYS_SIGN
702 SHORTPAIR(domlen),
703 SHORTPAIR(domlen),
704 SHORTPAIR(domoff),
705 0,0,
706 SHORTPAIR(hostlen),
707 SHORTPAIR(hostlen),
708 SHORTPAIR(hostoff),
709 0,0,
710 host /* this is empty */, domain /* this is empty */);
712 /* initial packet length */
713 size = 32 + hostlen + domlen;
714 #endif
716 DEBUG_OUT({
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|
721 NTLM2FLAG|
722 NTLMFLAG_NEGOTIATE_ALWAYS_SIGN),
723 NTLMFLAG_NEGOTIATE_OEM|
724 NTLMFLAG_REQUEST_TARGET|
725 NTLMFLAG_NEGOTIATE_NTLM_KEY|
726 NTLM2FLAG|
727 NTLMFLAG_NEGOTIATE_ALWAYS_SIGN);
728 print_flags(stderr,
729 NTLMFLAG_NEGOTIATE_OEM|
730 NTLMFLAG_REQUEST_TARGET|
731 NTLMFLAG_NEGOTIATE_NTLM_KEY|
732 NTLM2FLAG|
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);
740 if(size >0 ) {
741 Curl_safefree(*allocuserpwd);
742 *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
743 proxy?"Proxy-":"",
744 base64);
745 DEBUG_OUT(fprintf(stderr, "**** Header %s\n ", *allocuserpwd));
746 free(base64);
748 else
749 return CURLE_OUT_OF_MEMORY; /* FIX TODO */
751 break;
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"
758 (0x4e544c4d53535000)
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;
776 ULONG attrs;
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,
792 (char *) host,
793 ISC_REQ_CONFIDENTIALITY |
794 ISC_REQ_REPLAY_DETECT |
795 ISC_REQ_CONNECTION,
796 0, SECURITY_NETWORK_DREP, &type_2_desc,
797 0, &ntlm->c_handle, &type_3_desc,
798 &attrs, &tsDummy);
800 if(status != SEC_E_OK)
801 return CURLE_RECV_ERROR;
803 size = type_3.cbBuffer;
805 ntlm_sspi_cleanup(ntlm);
807 #else
808 int lmrespoff;
809 unsigned char lmresp[24]; /* fixed-size */
810 #if USE_NTRESPONSES
811 int ntrespoff;
812 unsigned char ntresp[24]; /* fixed-size */
813 #endif
814 size_t useroff;
815 const char *user;
816 size_t userlen;
818 user = strchr(userp, '\\');
819 if(!user)
820 user = strchr(userp, '/');
822 if(user) {
823 domain = userp;
824 domlen = (user - domain);
825 user++;
827 else
828 user = userp;
829 userlen = strlen(user);
831 if(gethostname(host, HOSTNAME_MAX)) {
832 infof(conn->data, "gethostname() failed, continuing without!");
833 hostlen = 0;
835 else {
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, '.');
841 if(dot)
842 *dot = '\0';
843 hostlen = strlen(host);
846 #if USE_NTLM2SESSION
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];
852 MD5_CTX MD5pw;
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);
861 /* Pad with zeros */
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);
868 MD5_Init(&MD5pw);
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 */
879 else {
880 #endif
882 #if USE_NTRESPONSES
883 unsigned char ntbuffer[0x18];
884 #endif
885 unsigned char lmbuffer[0x18];
887 #if USE_NTRESPONSES
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);
891 #endif
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 */
898 #if USE_NTLM2SESSION
900 #endif
902 lmrespoff = 64; /* size of the message header */
903 #if USE_NTRESPONSES
904 ntrespoff = lmrespoff + 0x18;
905 domoff = ntrespoff + 0x18;
906 #else
907 domoff = lmrespoff + 0x18;
908 #endif
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 */
956 /* domain string */
957 /* user string */
958 /* host string */
959 /* LanManager response */
960 /* NT response */
962 0, /* zero termination */
963 0,0,0, /* type-3 long, the 24 upper bits */
965 SHORTPAIR(0x18), /* LanManager response length, twice */
966 SHORTPAIR(0x18),
967 SHORTPAIR(lmrespoff),
968 0x0, 0x0,
970 #if USE_NTRESPONSES
971 SHORTPAIR(0x18), /* NT-response length, twice */
972 SHORTPAIR(0x18),
973 SHORTPAIR(ntrespoff),
974 0x0, 0x0,
975 #else
976 0x0, 0x0,
977 0x0, 0x0,
978 0x0, 0x0,
979 0x0, 0x0,
980 #endif
981 SHORTPAIR(domlen),
982 SHORTPAIR(domlen),
983 SHORTPAIR(domoff),
984 0x0, 0x0,
986 SHORTPAIR(userlen),
987 SHORTPAIR(userlen),
988 SHORTPAIR(useroff),
989 0x0, 0x0,
991 SHORTPAIR(hostlen),
992 SHORTPAIR(hostlen),
993 SHORTPAIR(hostoff),
994 0x0, 0x0,
996 0x0, 0x0,
997 0x0, 0x0,
998 0x0, 0x0,
999 0x0, 0x0,
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);
1008 size += 0x18;
1011 DEBUG_OUT({
1012 fprintf(stderr, "**** TYPE3 header lmresp=");
1013 print_hex(stderr, (char *)&ntlmbuf[lmrespoff], 0x18);
1016 #if USE_NTRESPONSES
1017 if(size < (sizeof(ntlmbuf) - 0x18)) {
1018 DEBUGASSERT(size == (size_t)ntrespoff);
1019 memcpy(&ntlmbuf[size], ntresp, 0x18);
1020 size += 0x18;
1023 DEBUG_OUT({
1024 fprintf(stderr, "\n ntresp=");
1025 print_hex(stderr, (char *)&ntlmbuf[ntrespoff], 0x18);
1028 #endif
1030 DEBUG_OUT({
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);
1047 size += domlen;
1049 DEBUGASSERT(size == useroff);
1050 memcpy(&ntlmbuf[size], user, userlen);
1051 size += userlen;
1053 DEBUGASSERT(size == hostoff);
1054 memcpy(&ntlmbuf[size], host, hostlen);
1055 size += 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],
1061 size-domoff)) {
1062 return CURLE_CONV_FAILED;
1064 #endif /* CURL_DOES_CONVERSIONS */
1066 #endif
1068 /* convert the binary blob into base64 */
1069 size = Curl_base64_encode(NULL, (char *)ntlmbuf, size, &base64);
1071 if(size >0 ) {
1072 Curl_safefree(*allocuserpwd);
1073 *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
1074 proxy?"Proxy-":"",
1075 base64);
1076 DEBUG_OUT(fprintf(stderr, "**** %s\n ", *allocuserpwd));
1077 free(base64);
1079 else
1080 return CURLE_OUT_OF_MEMORY; /* FIX TODO */
1082 ntlm->state = NTLMSTATE_TYPE3; /* we sent a type-3 */
1083 authp->done = TRUE;
1085 break;
1087 case NTLMSTATE_TYPE3:
1088 /* connection is already authenticated,
1089 * don't send a header in future requests */
1090 if(*allocuserpwd) {
1091 free(*allocuserpwd);
1092 *allocuserpwd=NULL;
1094 authp->done = TRUE;
1095 break;
1098 return CURLE_OK;
1102 void
1103 Curl_ntlm_cleanup(struct connectdata *conn)
1105 #ifdef USE_WINDOWS_SSPI
1106 ntlm_sspi_cleanup(&conn->ntlm);
1107 ntlm_sspi_cleanup(&conn->proxyntlm);
1108 #else
1109 (void)conn;
1110 #endif
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
1121 * secur32.dll)
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");
1129 else
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;
1143 return CURLE_OK;
1146 void Curl_ntlm_global_cleanup()
1148 if(s_hSecDll != NULL) {
1149 FreeLibrary(s_hSecDll);
1150 s_hSecDll = NULL;
1151 s_pSecFn = NULL;
1154 #endif
1156 #endif /* USE_NTLM */
1157 #endif /* !CURL_DISABLE_HTTP */