1/*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al. 9 * 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. 13 * 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. 17 * 18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 19 * KIND, either express or implied. 20 * 21 ***************************************************************************/ 22 23#include "curl_setup.h" 24 25#ifdef USE_NTLM 26 27/* 28 * NTLM details: 29 * 30 * http://davenport.sourceforge.net/ntlm.html 31 * http://www.innovation.ch/java/ntlm.html 32 */ 33 34#define DEBUG_ME 0 35 36#include "urldata.h" 37#include "non-ascii.h" 38#include "sendf.h" 39#include "curl_base64.h" 40#include "curl_ntlm_core.h" 41#include "curl_gethostname.h" 42#include "curl_multibyte.h" 43#include "warnless.h" 44#include "curl_memory.h" 45 46#ifdef USE_WINDOWS_SSPI 47# include "curl_sspi.h" 48#endif 49 50#include "sslgen.h" 51 52#define BUILDING_CURL_NTLM_MSGS_C 53#include "curl_ntlm_msgs.h" 54 55#define _MPRINTF_REPLACE /* use our functions only */ 56#include <curl/mprintf.h> 57 58/* The last #include file should be: */ 59#include "memdebug.h" 60 61/* "NTLMSSP" signature is always in ASCII regardless of the platform */ 62#define NTLMSSP_SIGNATURE "\x4e\x54\x4c\x4d\x53\x53\x50" 63 64#define SHORTPAIR(x) ((x) & 0xff), (((x) >> 8) & 0xff) 65#define LONGQUARTET(x) ((x) & 0xff), (((x) >> 8) & 0xff), \ 66 (((x) >> 16) & 0xff), (((x) >> 24) & 0xff) 67 68#if DEBUG_ME 69# define DEBUG_OUT(x) x 70static void ntlm_print_flags(FILE *handle, unsigned long flags) 71{ 72 if(flags & NTLMFLAG_NEGOTIATE_UNICODE) 73 fprintf(handle, "NTLMFLAG_NEGOTIATE_UNICODE "); 74 if(flags & NTLMFLAG_NEGOTIATE_OEM) 75 fprintf(handle, "NTLMFLAG_NEGOTIATE_OEM "); 76 if(flags & NTLMFLAG_REQUEST_TARGET) 77 fprintf(handle, "NTLMFLAG_REQUEST_TARGET "); 78 if(flags & (1<<3)) 79 fprintf(handle, "NTLMFLAG_UNKNOWN_3 "); 80 if(flags & NTLMFLAG_NEGOTIATE_SIGN) 81 fprintf(handle, "NTLMFLAG_NEGOTIATE_SIGN "); 82 if(flags & NTLMFLAG_NEGOTIATE_SEAL) 83 fprintf(handle, "NTLMFLAG_NEGOTIATE_SEAL "); 84 if(flags & NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE) 85 fprintf(handle, "NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE "); 86 if(flags & NTLMFLAG_NEGOTIATE_LM_KEY) 87 fprintf(handle, "NTLMFLAG_NEGOTIATE_LM_KEY "); 88 if(flags & NTLMFLAG_NEGOTIATE_NETWARE) 89 fprintf(handle, "NTLMFLAG_NEGOTIATE_NETWARE "); 90 if(flags & NTLMFLAG_NEGOTIATE_NTLM_KEY) 91 fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM_KEY "); 92 if(flags & (1<<10)) 93 fprintf(handle, "NTLMFLAG_UNKNOWN_10 "); 94 if(flags & NTLMFLAG_NEGOTIATE_ANONYMOUS) 95 fprintf(handle, "NTLMFLAG_NEGOTIATE_ANONYMOUS "); 96 if(flags & NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED) 97 fprintf(handle, "NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED "); 98 if(flags & NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED) 99 fprintf(handle, "NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED "); 100 if(flags & NTLMFLAG_NEGOTIATE_LOCAL_CALL) 101 fprintf(handle, "NTLMFLAG_NEGOTIATE_LOCAL_CALL "); 102 if(flags & NTLMFLAG_NEGOTIATE_ALWAYS_SIGN) 103 fprintf(handle, "NTLMFLAG_NEGOTIATE_ALWAYS_SIGN "); 104 if(flags & NTLMFLAG_TARGET_TYPE_DOMAIN) 105 fprintf(handle, "NTLMFLAG_TARGET_TYPE_DOMAIN "); 106 if(flags & NTLMFLAG_TARGET_TYPE_SERVER) 107 fprintf(handle, "NTLMFLAG_TARGET_TYPE_SERVER "); 108 if(flags & NTLMFLAG_TARGET_TYPE_SHARE) 109 fprintf(handle, "NTLMFLAG_TARGET_TYPE_SHARE "); 110 if(flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) 111 fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM2_KEY "); 112 if(flags & NTLMFLAG_REQUEST_INIT_RESPONSE) 113 fprintf(handle, "NTLMFLAG_REQUEST_INIT_RESPONSE "); 114 if(flags & NTLMFLAG_REQUEST_ACCEPT_RESPONSE) 115 fprintf(handle, "NTLMFLAG_REQUEST_ACCEPT_RESPONSE "); 116 if(flags & NTLMFLAG_REQUEST_NONNT_SESSION_KEY) 117 fprintf(handle, "NTLMFLAG_REQUEST_NONNT_SESSION_KEY "); 118 if(flags & NTLMFLAG_NEGOTIATE_TARGET_INFO) 119 fprintf(handle, "NTLMFLAG_NEGOTIATE_TARGET_INFO "); 120 if(flags & (1<<24)) 121 fprintf(handle, "NTLMFLAG_UNKNOWN_24 "); 122 if(flags & (1<<25)) 123 fprintf(handle, "NTLMFLAG_UNKNOWN_25 "); 124 if(flags & (1<<26)) 125 fprintf(handle, "NTLMFLAG_UNKNOWN_26 "); 126 if(flags & (1<<27)) 127 fprintf(handle, "NTLMFLAG_UNKNOWN_27 "); 128 if(flags & (1<<28)) 129 fprintf(handle, "NTLMFLAG_UNKNOWN_28 "); 130 if(flags & NTLMFLAG_NEGOTIATE_128) 131 fprintf(handle, "NTLMFLAG_NEGOTIATE_128 "); 132 if(flags & NTLMFLAG_NEGOTIATE_KEY_EXCHANGE) 133 fprintf(handle, "NTLMFLAG_NEGOTIATE_KEY_EXCHANGE "); 134 if(flags & NTLMFLAG_NEGOTIATE_56) 135 fprintf(handle, "NTLMFLAG_NEGOTIATE_56 "); 136} 137 138static void ntlm_print_hex(FILE *handle, const char *buf, size_t len) 139{ 140 const char *p = buf; 141 (void)handle; 142 fprintf(stderr, "0x"); 143 while(len-- > 0) 144 fprintf(stderr, "%02.2x", (unsigned int)*p++); 145} 146#else 147# define DEBUG_OUT(x) Curl_nop_stmt 148#endif 149 150#ifndef USE_WINDOWS_SSPI 151/* 152 * This function converts from the little endian format used in the 153 * incoming package to whatever endian format we're using natively. 154 * Argument is a pointer to a 4 byte buffer. 155 */ 156static unsigned int readint_le(unsigned char *buf) 157{ 158 return ((unsigned int)buf[0]) | ((unsigned int)buf[1] << 8) | 159 ((unsigned int)buf[2] << 16) | ((unsigned int)buf[3] << 24); 160} 161#endif 162 163/* 164 NTLM message structure notes: 165 166 A 'short' is a 'network short', a little-endian 16-bit unsigned value. 167 168 A 'long' is a 'network long', a little-endian, 32-bit unsigned value. 169 170 A 'security buffer' represents a triplet used to point to a buffer, 171 consisting of two shorts and one long: 172 173 1. A 'short' containing the length of the buffer content in bytes. 174 2. A 'short' containing the allocated space for the buffer in bytes. 175 3. A 'long' containing the offset to the start of the buffer in bytes, 176 from the beginning of the NTLM message. 177*/ 178 179/* 180 * Curl_ntlm_decode_type2_message() 181 * 182 * This is used to decode a ntlm type-2 message received from a HTTP or SASL 183 * based (such as SMTP, POP3 or IMAP) server. The message is first decoded 184 * from a base64 string into a raw ntlm message and checked for validity 185 * before the appropriate data for creating a type-3 message is written to 186 * the given ntlm data structure. 187 * 188 * Parameters: 189 * 190 * data [in] - Pointer to session handle. 191 * header [in] - Pointer to the input buffer. 192 * ntlm [in] - Pointer to ntlm data struct being used and modified. 193 * 194 * Returns CURLE_OK on success. 195 */ 196CURLcode Curl_ntlm_decode_type2_message(struct SessionHandle *data, 197 const char* header, 198 struct ntlmdata* ntlm) 199{ 200#ifndef USE_WINDOWS_SSPI 201 static const char type2_marker[] = { 0x02, 0x00, 0x00, 0x00 }; 202#endif 203 204 /* NTLM type-2 message structure: 205 206 Index Description Content 207 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP" 208 (0x4e544c4d53535000) 209 8 NTLM Message Type long (0x02000000) 210 12 Target Name security buffer 211 20 Flags long 212 24 Challenge 8 bytes 213 (32) Context 8 bytes (two consecutive longs) (*) 214 (40) Target Information security buffer (*) 215 (48) OS Version Structure 8 bytes (*) 216 32 (48) (56) Start of data block (*) 217 (*) -> Optional 218 */ 219 220 size_t size = 0; 221 unsigned char *buffer = NULL; 222 CURLcode error; 223 224#if defined(CURL_DISABLE_VERBOSE_STRINGS) || defined(USE_WINDOWS_SSPI) 225 (void)data; 226#endif 227 228 error = Curl_base64_decode(header, &buffer, &size); 229 if(error) 230 return error; 231 232 if(!buffer) { 233 infof(data, "NTLM handshake failure (unhandled condition)\n"); 234 return CURLE_REMOTE_ACCESS_DENIED; 235 } 236 237#ifdef USE_WINDOWS_SSPI 238 ntlm->type_2 = malloc(size + 1); 239 if(ntlm->type_2 == NULL) { 240 free(buffer); 241 return CURLE_OUT_OF_MEMORY; 242 } 243 ntlm->n_type_2 = curlx_uztoul(size); 244 memcpy(ntlm->type_2, buffer, size); 245#else 246 ntlm->flags = 0; 247 248 if((size < 32) || 249 (memcmp(buffer, NTLMSSP_SIGNATURE, 8) != 0) || 250 (memcmp(buffer + 8, type2_marker, sizeof(type2_marker)) != 0)) { 251 /* This was not a good enough type-2 message */ 252 free(buffer); 253 infof(data, "NTLM handshake failure (bad type-2 message)\n"); 254 return CURLE_REMOTE_ACCESS_DENIED; 255 } 256 257 ntlm->flags = readint_le(&buffer[20]); 258 memcpy(ntlm->nonce, &buffer[24], 8); 259 260 DEBUG_OUT({ 261 fprintf(stderr, "**** TYPE2 header flags=0x%08.8lx ", ntlm->flags); 262 ntlm_print_flags(stderr, ntlm->flags); 263 fprintf(stderr, "\n nonce="); 264 ntlm_print_hex(stderr, (char *)ntlm->nonce, 8); 265 fprintf(stderr, "\n****\n"); 266 fprintf(stderr, "**** Header %s\n ", header); 267 }); 268#endif 269 free(buffer); 270 271 return CURLE_OK; 272} 273 274#ifdef USE_WINDOWS_SSPI 275void Curl_ntlm_sspi_cleanup(struct ntlmdata *ntlm) 276{ 277 Curl_safefree(ntlm->type_2); 278 if(ntlm->has_handles) { 279 s_pSecFn->DeleteSecurityContext(&ntlm->c_handle); 280 s_pSecFn->FreeCredentialsHandle(&ntlm->handle); 281 ntlm->has_handles = 0; 282 } 283 if(ntlm->p_identity) { 284 Curl_safefree(ntlm->identity.User); 285 Curl_safefree(ntlm->identity.Password); 286 Curl_safefree(ntlm->identity.Domain); 287 ntlm->p_identity = NULL; 288 } 289} 290#endif 291 292#ifndef USE_WINDOWS_SSPI 293/* copy the source to the destination and fill in zeroes in every 294 other destination byte! */ 295static void unicodecpy(unsigned char *dest, 296 const char *src, size_t length) 297{ 298 size_t i; 299 for(i = 0; i < length; i++) { 300 dest[2 * i] = (unsigned char)src[i]; 301 dest[2 * i + 1] = '\0'; 302 } 303} 304#endif 305 306/* 307 * Curl_ntlm_create_type1_message() 308 * 309 * This is used to generate an already encoded NTLM type-1 message ready for 310 * sending to the recipient, be it a HTTP or SASL based (such as SMTP, POP3 311 * or IMAP) server, using the appropriate compile time crypo API. 312 * 313 * Parameters: 314 * 315 * userp [in] - The user name in the format User or Domain\User. 316 * passdwp [in] - The user's password. 317 * ntlm [in/out] - The ntlm data struct being used and modified. 318 * outptr [in/out] - The address where a pointer to newly allocated memory 319 * holding the result will be stored upon completion. 320 * outlen [out] - The length of the output message. 321 * 322 * Returns CURLE_OK on success. 323 */ 324CURLcode Curl_ntlm_create_type1_message(const char *userp, 325 const char *passwdp, 326 struct ntlmdata *ntlm, 327 char **outptr, 328 size_t *outlen) 329{ 330 /* NTLM type-1 message structure: 331 332 Index Description Content 333 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP" 334 (0x4e544c4d53535000) 335 8 NTLM Message Type long (0x01000000) 336 12 Flags long 337 (16) Supplied Domain security buffer (*) 338 (24) Supplied Workstation security buffer (*) 339 (32) OS Version Structure 8 bytes (*) 340 (32) (40) Start of data block (*) 341 (*) -> Optional 342 */ 343 344 unsigned char ntlmbuf[NTLM_BUFSIZE]; 345 size_t size; 346 347#ifdef USE_WINDOWS_SSPI 348 349 SecBuffer buf; 350 SecBufferDesc desc; 351 SECURITY_STATUS status; 352 unsigned long attrs; 353 xcharp_u useranddomain; 354 xcharp_u user, dup_user; 355 xcharp_u domain, dup_domain; 356 xcharp_u passwd, dup_passwd; 357 size_t domlen = 0; 358 TimeStamp tsDummy; /* For Windows 9x compatibility of SSPI calls */ 359 360 domain.const_tchar_ptr = TEXT(""); 361 362 Curl_ntlm_sspi_cleanup(ntlm); 363 364 if(userp && *userp) { 365 366 /* null initialize ntlm identity's data to allow proper cleanup */ 367 ntlm->p_identity = &ntlm->identity; 368 memset(ntlm->p_identity, 0, sizeof(*ntlm->p_identity)); 369 370 useranddomain.tchar_ptr = Curl_convert_UTF8_to_tchar((char *)userp); 371 if(!useranddomain.tchar_ptr) 372 return CURLE_OUT_OF_MEMORY; 373 374 user.const_tchar_ptr = _tcschr(useranddomain.const_tchar_ptr, TEXT('\\')); 375 if(!user.const_tchar_ptr) 376 user.const_tchar_ptr = _tcschr(useranddomain.const_tchar_ptr, TEXT('/')); 377 378 if(user.tchar_ptr) { 379 domain.tchar_ptr = useranddomain.tchar_ptr; 380 domlen = user.tchar_ptr - useranddomain.tchar_ptr; 381 user.tchar_ptr++; 382 } 383 else { 384 user.tchar_ptr = useranddomain.tchar_ptr; 385 domain.const_tchar_ptr = TEXT(""); 386 domlen = 0; 387 } 388 389 /* setup ntlm identity's user and length */ 390 dup_user.tchar_ptr = _tcsdup(user.tchar_ptr); 391 if(!dup_user.tchar_ptr) { 392 Curl_unicodefree(useranddomain.tchar_ptr); 393 return CURLE_OUT_OF_MEMORY; 394 } 395 ntlm->identity.User = dup_user.tbyte_ptr; 396 ntlm->identity.UserLength = curlx_uztoul(_tcslen(dup_user.tchar_ptr)); 397 dup_user.tchar_ptr = NULL; 398 399 /* setup ntlm identity's domain and length */ 400 dup_domain.tchar_ptr = malloc(sizeof(TCHAR) * (domlen + 1)); 401 if(!dup_domain.tchar_ptr) { 402 Curl_unicodefree(useranddomain.tchar_ptr); 403 return CURLE_OUT_OF_MEMORY; 404 } 405 _tcsncpy(dup_domain.tchar_ptr, domain.tchar_ptr, domlen); 406 *(dup_domain.tchar_ptr + domlen) = TEXT('\0'); 407 ntlm->identity.Domain = dup_domain.tbyte_ptr; 408 ntlm->identity.DomainLength = curlx_uztoul(domlen); 409 dup_domain.tchar_ptr = NULL; 410 411 Curl_unicodefree(useranddomain.tchar_ptr); 412 413 /* setup ntlm identity's password and length */ 414 passwd.tchar_ptr = Curl_convert_UTF8_to_tchar((char *)passwdp); 415 if(!passwd.tchar_ptr) 416 return CURLE_OUT_OF_MEMORY; 417 dup_passwd.tchar_ptr = _tcsdup(passwd.tchar_ptr); 418 if(!dup_passwd.tchar_ptr) { 419 Curl_unicodefree(passwd.tchar_ptr); 420 return CURLE_OUT_OF_MEMORY; 421 } 422 ntlm->identity.Password = dup_passwd.tbyte_ptr; 423 ntlm->identity.PasswordLength = 424 curlx_uztoul(_tcslen(dup_passwd.tchar_ptr)); 425 dup_passwd.tchar_ptr = NULL; 426 427 Curl_unicodefree(passwd.tchar_ptr); 428 429 /* setup ntlm identity's flags */ 430 ntlm->identity.Flags = SECFLAG_WINNT_AUTH_IDENTITY; 431 } 432 else 433 ntlm->p_identity = NULL; 434 435 status = s_pSecFn->AcquireCredentialsHandle(NULL, 436 (TCHAR *) TEXT("NTLM"), 437 SECPKG_CRED_OUTBOUND, NULL, 438 ntlm->p_identity, NULL, NULL, 439 &ntlm->handle, &tsDummy); 440 if(status != SEC_E_OK) 441 return CURLE_OUT_OF_MEMORY; 442 443 desc.ulVersion = SECBUFFER_VERSION; 444 desc.cBuffers = 1; 445 desc.pBuffers = &buf; 446 buf.cbBuffer = NTLM_BUFSIZE; 447 buf.BufferType = SECBUFFER_TOKEN; 448 buf.pvBuffer = ntlmbuf; 449 450 status = s_pSecFn->InitializeSecurityContext(&ntlm->handle, NULL, 451 (TCHAR *) TEXT(""), 452 ISC_REQ_CONFIDENTIALITY | 453 ISC_REQ_REPLAY_DETECT | 454 ISC_REQ_CONNECTION, 455 0, SECURITY_NETWORK_DREP, 456 NULL, 0, 457 &ntlm->c_handle, &desc, 458 &attrs, &tsDummy); 459 460 if(status == SEC_I_COMPLETE_AND_CONTINUE || 461 status == SEC_I_CONTINUE_NEEDED) 462 s_pSecFn->CompleteAuthToken(&ntlm->c_handle, &desc); 463 else if(status != SEC_E_OK) { 464 s_pSecFn->FreeCredentialsHandle(&ntlm->handle); 465 return CURLE_RECV_ERROR; 466 } 467 468 ntlm->has_handles = 1; 469 size = buf.cbBuffer; 470 471#else 472 473 const char *host = ""; /* empty */ 474 const char *domain = ""; /* empty */ 475 size_t hostlen = 0; 476 size_t domlen = 0; 477 size_t hostoff = 0; 478 size_t domoff = hostoff + hostlen; /* This is 0: remember that host and 479 domain are empty */ 480 (void)userp; 481 (void)passwdp; 482 (void)ntlm; 483 484#if USE_NTLM2SESSION 485#define NTLM2FLAG NTLMFLAG_NEGOTIATE_NTLM2_KEY 486#else 487#define NTLM2FLAG 0 488#endif 489 snprintf((char *)ntlmbuf, NTLM_BUFSIZE, 490 NTLMSSP_SIGNATURE "%c" 491 "\x01%c%c%c" /* 32-bit type = 1 */ 492 "%c%c%c%c" /* 32-bit NTLM flag field */ 493 "%c%c" /* domain length */ 494 "%c%c" /* domain allocated space */ 495 "%c%c" /* domain name offset */ 496 "%c%c" /* 2 zeroes */ 497 "%c%c" /* host length */ 498 "%c%c" /* host allocated space */ 499 "%c%c" /* host name offset */ 500 "%c%c" /* 2 zeroes */ 501 "%s" /* host name */ 502 "%s", /* domain string */ 503 0, /* trailing zero */ 504 0, 0, 0, /* part of type-1 long */ 505 506 LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM | 507 NTLMFLAG_REQUEST_TARGET | 508 NTLMFLAG_NEGOTIATE_NTLM_KEY | 509 NTLM2FLAG | 510 NTLMFLAG_NEGOTIATE_ALWAYS_SIGN), 511 SHORTPAIR(domlen), 512 SHORTPAIR(domlen), 513 SHORTPAIR(domoff), 514 0, 0, 515 SHORTPAIR(hostlen), 516 SHORTPAIR(hostlen), 517 SHORTPAIR(hostoff), 518 0, 0, 519 host, /* this is empty */ 520 domain /* this is empty */); 521 522 /* Initial packet length */ 523 size = 32 + hostlen + domlen; 524 525#endif 526 527 DEBUG_OUT({ 528 fprintf(stderr, "* TYPE1 header flags=0x%02.2x%02.2x%02.2x%02.2x " 529 "0x%08.8x ", 530 LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM | 531 NTLMFLAG_REQUEST_TARGET | 532 NTLMFLAG_NEGOTIATE_NTLM_KEY | 533 NTLM2FLAG | 534 NTLMFLAG_NEGOTIATE_ALWAYS_SIGN), 535 NTLMFLAG_NEGOTIATE_OEM | 536 NTLMFLAG_REQUEST_TARGET | 537 NTLMFLAG_NEGOTIATE_NTLM_KEY | 538 NTLM2FLAG | 539 NTLMFLAG_NEGOTIATE_ALWAYS_SIGN); 540 ntlm_print_flags(stderr, 541 NTLMFLAG_NEGOTIATE_OEM | 542 NTLMFLAG_REQUEST_TARGET | 543 NTLMFLAG_NEGOTIATE_NTLM_KEY | 544 NTLM2FLAG | 545 NTLMFLAG_NEGOTIATE_ALWAYS_SIGN); 546 fprintf(stderr, "\n****\n"); 547 }); 548 549 /* Return with binary blob encoded into base64 */ 550 return Curl_base64_encode(NULL, (char *)ntlmbuf, size, outptr, outlen); 551} 552 553/* 554 * Curl_ntlm_create_type3_message() 555 * 556 * This is used to generate an already encoded NTLM type-3 message ready for 557 * sending to the recipient, be it a HTTP or SASL based (such as SMTP, POP3 558 * or IMAP) server, using the appropriate compile time crypo API. 559 * 560 * Parameters: 561 * 562 * data [in] - The session handle. 563 * userp [in] - The user name in the format User or Domain\User. 564 * passdwp [in] - The user's password. 565 * ntlm [in/out] - The ntlm data struct being used and modified. 566 * outptr [in/out] - The address where a pointer to newly allocated memory 567 * holding the result will be stored upon completion. 568 * outlen [out] - The length of the output message. 569 * 570 * Returns CURLE_OK on success. 571 */ 572CURLcode Curl_ntlm_create_type3_message(struct SessionHandle *data, 573 const char *userp, 574 const char *passwdp, 575 struct ntlmdata *ntlm, 576 char **outptr, 577 size_t *outlen) 578{ 579 /* NTLM type-3 message structure: 580 581 Index Description Content 582 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP" 583 (0x4e544c4d53535000) 584 8 NTLM Message Type long (0x03000000) 585 12 LM/LMv2 Response security buffer 586 20 NTLM/NTLMv2 Response security buffer 587 28 Target Name security buffer 588 36 User Name security buffer 589 44 Workstation Name security buffer 590 (52) Session Key security buffer (*) 591 (60) Flags long (*) 592 (64) OS Version Structure 8 bytes (*) 593 52 (64) (72) Start of data block 594 (*) -> Optional 595 */ 596 597 unsigned char ntlmbuf[NTLM_BUFSIZE]; 598 size_t size; 599 600#ifdef USE_WINDOWS_SSPI 601 SecBuffer type_2; 602 SecBuffer type_3; 603 SecBufferDesc type_2_desc; 604 SecBufferDesc type_3_desc; 605 SECURITY_STATUS status; 606 unsigned long attrs; 607 TimeStamp tsDummy; /* For Windows 9x compatibility of SSPI calls */ 608 609 (void)passwdp; 610 (void)userp; 611 (void)data; 612 613 type_2_desc.ulVersion = type_3_desc.ulVersion = SECBUFFER_VERSION; 614 type_2_desc.cBuffers = type_3_desc.cBuffers = 1; 615 type_2_desc.pBuffers = &type_2; 616 type_3_desc.pBuffers = &type_3; 617 618 type_2.BufferType = SECBUFFER_TOKEN; 619 type_2.pvBuffer = ntlm->type_2; 620 type_2.cbBuffer = ntlm->n_type_2; 621 type_3.BufferType = SECBUFFER_TOKEN; 622 type_3.pvBuffer = ntlmbuf; 623 type_3.cbBuffer = NTLM_BUFSIZE; 624 625 status = s_pSecFn->InitializeSecurityContext(&ntlm->handle, 626 &ntlm->c_handle, 627 (TCHAR *) TEXT(""), 628 ISC_REQ_CONFIDENTIALITY | 629 ISC_REQ_REPLAY_DETECT | 630 ISC_REQ_CONNECTION, 631 0, SECURITY_NETWORK_DREP, 632 &type_2_desc, 633 0, &ntlm->c_handle, 634 &type_3_desc, 635 &attrs, &tsDummy); 636 if(status != SEC_E_OK) 637 return CURLE_RECV_ERROR; 638 639 size = type_3.cbBuffer; 640 641 Curl_ntlm_sspi_cleanup(ntlm); 642 643#else 644 int lmrespoff; 645 unsigned char lmresp[24]; /* fixed-size */ 646#if USE_NTRESPONSES 647 int ntrespoff; 648 unsigned char ntresp[24]; /* fixed-size */ 649#endif 650 bool unicode = (ntlm->flags & NTLMFLAG_NEGOTIATE_UNICODE) ? TRUE : FALSE; 651 char host[HOSTNAME_MAX + 1] = ""; 652 const char *user; 653 const char *domain = ""; 654 size_t hostoff = 0; 655 size_t useroff = 0; 656 size_t domoff = 0; 657 size_t hostlen = 0; 658 size_t userlen = 0; 659 size_t domlen = 0; 660 CURLcode res; 661 662 user = strchr(userp, '\\'); 663 if(!user) 664 user = strchr(userp, '/'); 665 666 if(user) { 667 domain = userp; 668 domlen = (user - domain); 669 user++; 670 } 671 else 672 user = userp; 673 674 if(user) 675 userlen = strlen(user); 676 677 /* Get the machine's un-qualified host name as NTLM doesn't like the fully 678 qualified domain name */ 679 if(Curl_gethostname(host, sizeof(host))) { 680 infof(data, "gethostname() failed, continuing without!\n"); 681 hostlen = 0; 682 } 683 else { 684 hostlen = strlen(host); 685 } 686 687 if(unicode) { 688 domlen = domlen * 2; 689 userlen = userlen * 2; 690 hostlen = hostlen * 2; 691 } 692 693#if USE_NTLM2SESSION 694 /* We don't support NTLM2 if we don't have USE_NTRESPONSES */ 695 if(ntlm->flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) { 696 unsigned char ntbuffer[0x18]; 697 unsigned char tmp[0x18]; 698 unsigned char md5sum[MD5_DIGEST_LENGTH]; 699 unsigned char entropy[8]; 700 701 /* Need to create 8 bytes random data */ 702 Curl_ssl_random(data, entropy, sizeof(entropy)); 703 704 /* 8 bytes random data as challenge in lmresp */ 705 memcpy(lmresp, entropy, 8); 706 707 /* Pad with zeros */ 708 memset(lmresp + 8, 0, 0x10); 709 710 /* Fill tmp with challenge(nonce?) + entropy */ 711 memcpy(tmp, &ntlm->nonce[0], 8); 712 memcpy(tmp + 8, entropy, 8); 713 714 Curl_ssl_md5sum(tmp, 16, md5sum, MD5_DIGEST_LENGTH); 715 716 /* We shall only use the first 8 bytes of md5sum, but the des 717 code in Curl_ntlm_core_lm_resp only encrypt the first 8 bytes */ 718 if(CURLE_OUT_OF_MEMORY == 719 Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer)) 720 return CURLE_OUT_OF_MEMORY; 721 Curl_ntlm_core_lm_resp(ntbuffer, md5sum, ntresp); 722 723 /* End of NTLM2 Session code */ 724 } 725 else 726#endif 727 { 728 729#if USE_NTRESPONSES 730 unsigned char ntbuffer[0x18]; 731#endif 732 unsigned char lmbuffer[0x18]; 733 734#if USE_NTRESPONSES 735 if(CURLE_OUT_OF_MEMORY == 736 Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer)) 737 return CURLE_OUT_OF_MEMORY; 738 Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], ntresp); 739#endif 740 741 Curl_ntlm_core_mk_lm_hash(data, passwdp, lmbuffer); 742 Curl_ntlm_core_lm_resp(lmbuffer, &ntlm->nonce[0], lmresp); 743 /* A safer but less compatible alternative is: 744 * Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], lmresp); 745 * See http://davenport.sourceforge.net/ntlm.html#ntlmVersion2 */ 746 } 747 748 lmrespoff = 64; /* size of the message header */ 749#if USE_NTRESPONSES 750 ntrespoff = lmrespoff + 0x18; 751 domoff = ntrespoff + 0x18; 752#else 753 domoff = lmrespoff + 0x18; 754#endif 755 useroff = domoff + domlen; 756 hostoff = useroff + userlen; 757 758 /* Create the big type-3 message binary blob */ 759 size = snprintf((char *)ntlmbuf, NTLM_BUFSIZE, 760 NTLMSSP_SIGNATURE "%c" 761 "\x03%c%c%c" /* 32-bit type = 3 */ 762 763 "%c%c" /* LanManager length */ 764 "%c%c" /* LanManager allocated space */ 765 "%c%c" /* LanManager offset */ 766 "%c%c" /* 2 zeroes */ 767 768 "%c%c" /* NT-response length */ 769 "%c%c" /* NT-response allocated space */ 770 "%c%c" /* NT-response offset */ 771 "%c%c" /* 2 zeroes */ 772 773 "%c%c" /* domain length */ 774 "%c%c" /* domain allocated space */ 775 "%c%c" /* domain name offset */ 776 "%c%c" /* 2 zeroes */ 777 778 "%c%c" /* user length */ 779 "%c%c" /* user allocated space */ 780 "%c%c" /* user offset */ 781 "%c%c" /* 2 zeroes */ 782 783 "%c%c" /* host length */ 784 "%c%c" /* host allocated space */ 785 "%c%c" /* host offset */ 786 "%c%c" /* 2 zeroes */ 787 788 "%c%c" /* session key length (unknown purpose) */ 789 "%c%c" /* session key allocated space (unknown purpose) */ 790 "%c%c" /* session key offset (unknown purpose) */ 791 "%c%c" /* 2 zeroes */ 792 793 "%c%c%c%c", /* flags */ 794 795 /* domain string */ 796 /* user string */ 797 /* host string */ 798 /* LanManager response */ 799 /* NT response */ 800 801 0, /* zero termination */ 802 0, 0, 0, /* type-3 long, the 24 upper bits */ 803 804 SHORTPAIR(0x18), /* LanManager response length, twice */ 805 SHORTPAIR(0x18), 806 SHORTPAIR(lmrespoff), 807 0x0, 0x0, 808 809#if USE_NTRESPONSES 810 SHORTPAIR(0x18), /* NT-response length, twice */ 811 SHORTPAIR(0x18), 812 SHORTPAIR(ntrespoff), 813 0x0, 0x0, 814#else 815 0x0, 0x0, 816 0x0, 0x0, 817 0x0, 0x0, 818 0x0, 0x0, 819#endif 820 SHORTPAIR(domlen), 821 SHORTPAIR(domlen), 822 SHORTPAIR(domoff), 823 0x0, 0x0, 824 825 SHORTPAIR(userlen), 826 SHORTPAIR(userlen), 827 SHORTPAIR(useroff), 828 0x0, 0x0, 829 830 SHORTPAIR(hostlen), 831 SHORTPAIR(hostlen), 832 SHORTPAIR(hostoff), 833 0x0, 0x0, 834 835 0x0, 0x0, 836 0x0, 0x0, 837 0x0, 0x0, 838 0x0, 0x0, 839 840 LONGQUARTET(ntlm->flags)); 841 842 DEBUGASSERT(size == 64); 843 DEBUGASSERT(size == (size_t)lmrespoff); 844 845 /* We append the binary hashes */ 846 if(size < (NTLM_BUFSIZE - 0x18)) { 847 memcpy(&ntlmbuf[size], lmresp, 0x18); 848 size += 0x18; 849 } 850 851 DEBUG_OUT({ 852 fprintf(stderr, "**** TYPE3 header lmresp="); 853 ntlm_print_hex(stderr, (char *)&ntlmbuf[lmrespoff], 0x18); 854 }); 855 856#if USE_NTRESPONSES 857 if(size < (NTLM_BUFSIZE - 0x18)) { 858 DEBUGASSERT(size == (size_t)ntrespoff); 859 memcpy(&ntlmbuf[size], ntresp, 0x18); 860 size += 0x18; 861 } 862 863 DEBUG_OUT({ 864 fprintf(stderr, "\n ntresp="); 865 ntlm_print_hex(stderr, (char *)&ntlmbuf[ntrespoff], 0x18); 866 }); 867 868#endif 869 870 DEBUG_OUT({ 871 fprintf(stderr, "\n flags=0x%02.2x%02.2x%02.2x%02.2x 0x%08.8x ", 872 LONGQUARTET(ntlm->flags), ntlm->flags); 873 ntlm_print_flags(stderr, ntlm->flags); 874 fprintf(stderr, "\n****\n"); 875 }); 876 877 /* Make sure that the domain, user and host strings fit in the 878 buffer before we copy them there. */ 879 if(size + userlen + domlen + hostlen >= NTLM_BUFSIZE) { 880 failf(data, "user + domain + host name too big"); 881 return CURLE_OUT_OF_MEMORY; 882 } 883 884 DEBUGASSERT(size == domoff); 885 if(unicode) 886 unicodecpy(&ntlmbuf[size], domain, domlen / 2); 887 else 888 memcpy(&ntlmbuf[size], domain, domlen); 889 890 size += domlen; 891 892 DEBUGASSERT(size == useroff); 893 if(unicode) 894 unicodecpy(&ntlmbuf[size], user, userlen / 2); 895 else 896 memcpy(&ntlmbuf[size], user, userlen); 897 898 size += userlen; 899 900 DEBUGASSERT(size == hostoff); 901 if(unicode) 902 unicodecpy(&ntlmbuf[size], host, hostlen / 2); 903 else 904 memcpy(&ntlmbuf[size], host, hostlen); 905 906 size += hostlen; 907 908 /* Convert domain, user, and host to ASCII but leave the rest as-is */ 909 res = Curl_convert_to_network(data, (char *)&ntlmbuf[domoff], 910 size - domoff); 911 if(res) 912 return CURLE_CONV_FAILED; 913 914#endif 915 916 /* Return with binary blob encoded into base64 */ 917 return Curl_base64_encode(NULL, (char *)ntlmbuf, size, outptr, outlen); 918} 919 920#endif /* USE_NTLM */ 921