ENH: typo
[cmake.git] / Utilities / cmcurl / http_ntlm.c
blobca5b7f45a02fcfd4ac73c990e1327919894d1f5a
1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
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 ***************************************************************************/
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 #include "urldata.h"
52 #include "easyif.h" /* for Curl_convert_... prototypes */
53 #include "sendf.h"
54 #include "strequal.h"
55 #include "base64.h"
56 #include "http_ntlm.h"
57 #include "url.h"
58 #include "memory.h"
59 #include "ssluse.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 */
83 #define DESKEY(x) x
84 #define DESKEYARG(x) x
85 #else
86 /* Modern version */
87 #define DESKEYARG(x) *x
88 #define DESKEY(x) &x
89 #endif
91 #else
93 #include <rpc.h>
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;
100 #endif
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
116 4 bytes buffer*/
118 return ((unsigned int)buf[0]) | ((unsigned int)buf[1] << 8) |
119 ((unsigned int)buf[2] << 16) | ((unsigned int)buf[3] << 24);
121 #endif
123 #if DEBUG_ME
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 ");
133 if(flags & (1<<3))
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 ");
147 if(flags & (1<<10))
148 fprintf(handle, "NTLMFLAG_UNKNOWN_10 ");
149 if(flags & (1<<11))
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 ");
175 if(flags & (1<<24))
176 fprintf(handle, "NTLMFLAG_UNKNOWN_24 ");
177 if(flags & (1<<25))
178 fprintf(handle, "NTLMFLAG_UNKNOWN_25 ");
179 if(flags & (1<<26))
180 fprintf(handle, "NTLMFLAG_UNKNOWN_26 ");
181 if(flags & (1<<27))
182 fprintf(handle, "NTLMFLAG_UNKNOWN_27 ");
183 if(flags & (1<<28))
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)
195 const char *p = buf;
196 fprintf(stderr, "0x");
197 while (len-- > 0)
198 fprintf(stderr, "%02.2x", (unsigned int)*p++);
200 #else
201 # define DEBUG_OUT(x)
202 #endif
205 (*) = A "security buffer" is a triplet consisting of two shorts and one
206 long:
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:
218 header */
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 };
224 #endif
226 ntlm = proxy?&conn->proxyntlm:&conn->ntlm;
228 /* skip initial whitespaces */
229 while(*header && ISSPACE(*header))
230 header++;
232 if(checkprefix("NTLM", header)) {
233 header += strlen("NTLM");
235 while(*header && ISSPACE(*header))
236 header++;
238 if(*header) {
239 /* We got a type-2 message here:
241 Index Description Content
242 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
243 (0x4e544c4d53535000)
244 8 NTLM Message Type long (0x02000000)
245 12 Target Name security buffer(*)
246 20 Flags long
247 24 Challenge 8 bytes
248 (32) Context (optional) 8 bytes (two consecutive longs)
249 (40) Target Information (optional) security buffer(*)
250 32 (48) start of data block
252 size_t size;
253 unsigned char *buffer;
254 size = Curl_base64_decode(header, &buffer);
255 if(!buffer)
256 return CURLNTLM_BAD;
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) {
263 free(buffer);
264 return CURLE_OUT_OF_MEMORY;
266 ntlm->n_type_2 = size;
267 memcpy(ntlm->type_2, buffer, size);
268 #else
269 ntlm->flags = 0;
271 if((size < 32) ||
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 */
275 free(buffer);
276 return CURLNTLM_BAD;
279 ntlm->flags = readint_le(&buffer[20]);
280 memcpy(ntlm->nonce, &buffer[24], 8);
282 DEBUG_OUT({
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);
291 free(buffer);
292 #endif
294 else {
295 if(ntlm->state >= NTLMSTATE_TYPE1)
296 return CURLNTLM_BAD;
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))
313 DES_cblock key;
315 key[0] = key_56[0];
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)
337 DES_key_schedule ks;
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,
357 char *password,
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!@#$% */
364 unsigned int i;
365 size_t len = strlen(password);
367 if (len > 14)
368 len = 14;
370 for (i=0; i<len; i++)
371 pw[i] = (unsigned char)toupper(password[i]);
373 for (; i<14; i++)
374 pw[i] = 0;
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.
381 if(data)
382 Curl_convert_to_network(data, (char *)pw, 14);
383 #else
384 (void)data;
385 #endif
388 /* Create LanManager hashed password. */
390 DES_key_schedule ks;
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);
404 #if USE_NTRESPONSES
405 static void utf8_to_unicode_le(unsigned char *dest, const char *src,
406 size_t srclen)
408 size_t i;
409 for (i=0; i<srclen; i++) {
410 dest[2*i] = (unsigned char)src[i];
411 dest[2*i+1] = '\0';
416 * Set up nt hashed passwords
418 static void mk_nt_hash(struct SessionHandle *data,
419 char *password,
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.
432 if(data)
433 Curl_convert_to_network(data, (char *)pw, len*2);
434 #else
435 (void)data;
436 #endif
439 /* Create NT hashed password. */
440 MD4_CTX MD4;
442 MD4_Init(&MD4);
443 MD4_Update(&MD4, pw, 2*len);
444 MD4_Final(ntbuffer, &MD4);
446 memset(ntbuffer + 16, 0, 21 - 16);
449 free(pw);
451 #endif
454 #endif
456 #ifdef USE_WINDOWS_SSPI
458 static void
459 ntlm_sspi_cleanup(struct ntlmdata *ntlm)
461 if (ntlm->type_2) {
462 free(ntlm->type_2);
463 ntlm->type_2 = NULL;
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;
478 #endif
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,
488 bool proxy)
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 */
497 #endif
498 size_t size;
499 char *base64=NULL;
500 unsigned char ntlmbuf[1024]; /* enough, unless the user+host+domain is very
501 long */
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 */
505 char **allocuserpwd;
507 /* point to the name and password for this */
508 char *userp;
509 char *passwdp;
510 /* point to the correct struct with this */
511 struct ntlmdata *ntlm;
512 struct auth *authp;
514 curlassert(conn);
515 curlassert(conn->data);
517 if(proxy) {
518 allocuserpwd = &conn->allocptr.proxyuserpwd;
519 userp = conn->proxyuser;
520 passwdp = conn->proxypasswd;
521 ntlm = &conn->proxyntlm;
522 authp = &conn->data->state.authproxy;
524 else {
525 allocuserpwd = &conn->allocptr.userpwd;
526 userp = conn->user;
527 passwdp = conn->passwd;
528 ntlm = &conn->ntlm;
529 authp = &conn->data->state.authhost;
531 authp->done = FALSE;
533 /* not set means empty */
534 if(!userp)
535 userp=(char *)"";
537 if(!passwdp)
538 passwdp=(char *)"";
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
546 * secur32.dll)
548 OSVERSIONINFO osver;
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");
554 else
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;
567 #endif
569 switch(ntlm->state) {
570 case NTLMSTATE_TYPE1:
571 default: /* for the weird cases we (re)start here */
572 #ifdef USE_WINDOWS_SSPI
574 SecBuffer buf;
575 SecBufferDesc desc;
576 SECURITY_STATUS status;
577 ULONG attrs;
578 const char *user;
579 int domlen;
580 TimeStamp tsDummy; /* For Windows 9x compatibility of SPPI calls */
582 ntlm_sspi_cleanup(ntlm);
584 user = strchr(userp, '\\');
585 if (!user)
586 user = strchr(userp, '/');
588 if (user) {
589 domain = userp;
590 domlen = user - userp;
591 user++;
593 else {
594 user = userp;
595 domain = "";
596 domlen = 0;
599 if (user && *user) {
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;
618 else {
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
625 ) != SEC_E_OK) {
626 return CURLE_OUT_OF_MEMORY;
629 desc.ulVersion = SECBUFFER_VERSION;
630 desc.cBuffers = 1;
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,
637 (char *) host,
638 ISC_REQ_CONFIDENTIALITY |
639 ISC_REQ_REPLAY_DETECT |
640 ISC_REQ_CONNECTION,
641 0, SECURITY_NETWORK_DREP,
642 NULL, 0,
643 &ntlm->c_handle, &desc,
644 &attrs, &tsDummy);
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;
656 size = buf.cbBuffer;
658 #else
659 hostoff = 0;
660 domoff = hostoff + hostlen; /* This is 0: remember that host and domain
661 are empty */
663 /* Create and send a type-1 message:
665 Index Description Content
666 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
667 (0x4e544c4d53535000)
668 8 NTLM Message Type long (0x01000000)
669 12 Flags long
670 16 Supplied Domain security buffer(*)
671 24 Supplied Workstation security buffer(*)
672 32 start of data block
675 #if USE_NTLM2SESSION
676 #define NTLM2FLAG NTLMFLAG_NEGOTIATE_NTLM2_KEY
677 #else
678 #define NTLM2FLAG 0
679 #endif
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 */
691 "%s" /* host name */
692 "%s", /* domain string */
693 0, /* trailing zero */
694 0,0,0, /* part of type-1 long */
696 LONGQUARTET(
697 NTLMFLAG_NEGOTIATE_OEM|
698 NTLMFLAG_REQUEST_TARGET|
699 NTLMFLAG_NEGOTIATE_NTLM_KEY|
700 NTLM2FLAG|
701 NTLMFLAG_NEGOTIATE_ALWAYS_SIGN
703 SHORTPAIR(domlen),
704 SHORTPAIR(domlen),
705 SHORTPAIR(domoff),
706 0,0,
707 SHORTPAIR(hostlen),
708 SHORTPAIR(hostlen),
709 SHORTPAIR(hostoff),
710 0,0,
711 host /* this is empty */, domain /* this is empty */);
713 /* initial packet length */
714 size = 32 + hostlen + domlen;
715 #endif
717 DEBUG_OUT({
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|
722 NTLM2FLAG|
723 NTLMFLAG_NEGOTIATE_ALWAYS_SIGN),
724 NTLMFLAG_NEGOTIATE_OEM|
725 NTLMFLAG_REQUEST_TARGET|
726 NTLMFLAG_NEGOTIATE_NTLM_KEY|
727 NTLM2FLAG|
728 NTLMFLAG_NEGOTIATE_ALWAYS_SIGN);
729 print_flags(stderr,
730 NTLMFLAG_NEGOTIATE_OEM|
731 NTLMFLAG_REQUEST_TARGET|
732 NTLMFLAG_NEGOTIATE_NTLM_KEY|
733 NTLM2FLAG|
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);
741 if(size >0 ) {
742 Curl_safefree(*allocuserpwd);
743 *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
744 proxy?"Proxy-":"",
745 base64);
746 DEBUG_OUT(fprintf(stderr, "**** Header %s\n ", *allocuserpwd));
747 free(base64);
749 else
750 return CURLE_OUT_OF_MEMORY; /* FIX TODO */
752 break;
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"
759 (0x4e544c4d53535000)
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;
777 ULONG attrs;
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,
793 (char *) host,
794 ISC_REQ_CONFIDENTIALITY |
795 ISC_REQ_REPLAY_DETECT |
796 ISC_REQ_CONNECTION,
797 0, SECURITY_NETWORK_DREP, &type_2_desc,
798 0, &ntlm->c_handle, &type_3_desc,
799 &attrs, &tsDummy);
801 if (status != SEC_E_OK)
802 return CURLE_RECV_ERROR;
804 size = type_3.cbBuffer;
806 ntlm_sspi_cleanup(ntlm);
808 #else
809 int lmrespoff;
810 unsigned char lmresp[24]; /* fixed-size */
811 #if USE_NTRESPONSES
812 int ntrespoff;
813 unsigned char ntresp[24]; /* fixed-size */
814 #endif
815 size_t useroff;
816 const char *user;
817 size_t userlen;
819 user = strchr(userp, '\\');
820 if(!user)
821 user = strchr(userp, '/');
823 if (user) {
824 domain = userp;
825 domlen = (user - domain);
826 user++;
828 else
829 user = userp;
830 userlen = strlen(user);
832 if (gethostname(host, HOSTNAME_MAX)) {
833 infof(conn->data, "gethostname() failed, continuing without!");
834 hostlen = 0;
836 else {
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, '.');
842 if (dot)
843 *dot = '\0';
844 hostlen = strlen(host);
847 #if USE_NTLM2SESSION
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];
853 MD5_CTX MD5;
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);
862 /* Pad with zeros */
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);
869 MD5_Init(&MD5);
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 */
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 mk_nt_hash(conn->data, passwdp, ntbuffer);
889 lm_resp(ntbuffer, &ntlm->nonce[0], ntresp);
890 #endif
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 */
897 #if USE_NTLM2SESSION
899 #endif
901 lmrespoff = 64; /* size of the message header */
902 #if USE_NTRESPONSES
903 ntrespoff = lmrespoff + 0x18;
904 domoff = ntrespoff + 0x18;
905 #else
906 domoff = lmrespoff + 0x18;
907 #endif
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 */
948 /* domain string */
949 /* user string */
950 /* host string */
951 /* LanManager response */
952 /* NT response */
954 0, /* zero termination */
955 0,0,0, /* type-3 long, the 24 upper bits */
957 SHORTPAIR(0x18), /* LanManager response length, twice */
958 SHORTPAIR(0x18),
959 SHORTPAIR(lmrespoff),
960 0x0, 0x0,
962 #if USE_NTRESPONSES
963 SHORTPAIR(0x18), /* NT-response length, twice */
964 SHORTPAIR(0x18),
965 SHORTPAIR(ntrespoff),
966 0x0, 0x0,
967 #else
968 0x0, 0x0,
969 0x0, 0x0,
970 0x0, 0x0,
971 0x0, 0x0,
972 #endif
973 SHORTPAIR(domlen),
974 SHORTPAIR(domlen),
975 SHORTPAIR(domoff),
976 0x0, 0x0,
978 SHORTPAIR(userlen),
979 SHORTPAIR(userlen),
980 SHORTPAIR(useroff),
981 0x0, 0x0,
983 SHORTPAIR(hostlen),
984 SHORTPAIR(hostlen),
985 SHORTPAIR(hostoff),
986 0x0, 0x0,
988 0x0, 0x0,
989 0x0, 0x0,
990 0x0, 0x0,
991 0x0, 0x0,
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);
1000 size += 0x18;
1003 DEBUG_OUT({
1004 fprintf(stderr, "**** TYPE3 header lmresp=");
1005 print_hex(stderr, (char *)&ntlmbuf[lmrespoff], 0x18);
1008 #if USE_NTRESPONSES
1009 if(size < (sizeof(ntlmbuf) - 0x18)) {
1010 DEBUG_OUT(assert(size == ntrespoff));
1011 memcpy(&ntlmbuf[size], ntresp, 0x18);
1012 size += 0x18;
1015 DEBUG_OUT({
1016 fprintf(stderr, "\n ntresp=");
1017 print_hex(stderr, (char *)&ntlmbuf[ntrespoff], 0x18);
1020 #endif
1022 DEBUG_OUT({
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);
1039 size += domlen;
1041 curlassert(size == useroff);
1042 memcpy(&ntlmbuf[size], user, userlen);
1043 size += userlen;
1045 curlassert(size == hostoff);
1046 memcpy(&ntlmbuf[size], host, hostlen);
1047 size += 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],
1053 size-domoff)) {
1054 return CURLE_CONV_FAILED;
1056 #endif /* CURL_DOES_CONVERSIONS */
1058 #endif
1060 /* convert the binary blob into base64 */
1061 size = Curl_base64_encode(NULL, (char *)ntlmbuf, size, &base64);
1063 if(size >0 ) {
1064 Curl_safefree(*allocuserpwd);
1065 *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
1066 proxy?"Proxy-":"",
1067 base64);
1068 DEBUG_OUT(fprintf(stderr, "**** %s\n ", *allocuserpwd));
1069 free(base64);
1071 else
1072 return CURLE_OUT_OF_MEMORY; /* FIX TODO */
1074 ntlm->state = NTLMSTATE_TYPE3; /* we sent a type-3 */
1075 authp->done = TRUE;
1077 break;
1079 case NTLMSTATE_TYPE3:
1080 /* connection is already authenticated,
1081 * don't send a header in future requests */
1082 if(*allocuserpwd) {
1083 free(*allocuserpwd);
1084 *allocuserpwd=NULL;
1086 authp->done = TRUE;
1087 break;
1090 return CURLE_OK;
1094 void
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);
1102 s_hSecDll = NULL;
1103 s_pSecFn = NULL;
1105 #else
1106 (void)conn;
1107 #endif
1110 #endif /* USE_NTLM */
1111 #endif /* !CURL_DISABLE_HTTP */