1/*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1998 - 2014, 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 "vtls/vtls.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 162/* 163 * This function converts from the little endian format used in the incoming 164 * package to whatever endian format we're using natively. Argument is a 165 * pointer to a 2 byte buffer. 166 */ 167static unsigned int readshort_le(unsigned char *buf) 168{ 169 return ((unsigned int)buf[0]) | ((unsigned int)buf[1] << 8); 170} 171 172/* 173 * Curl_ntlm_decode_type2_target() 174 * 175 * This is used to decode the "target info" in the ntlm type-2 message 176 * received. 177 * 178 * Parameters: 179 * 180 * data [in] - Pointer to the session handle 181 * buffer [in] - The decoded base64 ntlm header of Type 2 182 * size [in] - The input buffer size, atleast 32 bytes 183 * ntlm [in] - Pointer to ntlm data struct being used and modified. 184 * 185 * Returns CURLE_OK on success. 186 */ 187CURLcode Curl_ntlm_decode_type2_target(struct SessionHandle *data, 188 unsigned char *buffer, 189 size_t size, 190 struct ntlmdata *ntlm) 191{ 192 unsigned int target_info_len = 0; 193 unsigned int target_info_offset = 0; 194 195 Curl_safefree(ntlm->target_info); 196 ntlm->target_info_len = 0; 197 198 if(size >= 48) { 199 target_info_len = readshort_le(&buffer[40]); 200 target_info_offset = readint_le(&buffer[44]); 201 if(target_info_len > 0) { 202 if(((target_info_offset + target_info_len) > size) || 203 (target_info_offset < 48)) { 204 infof(data, "NTLM handshake failure (bad type-2 message). " 205 "Target Info Offset Len is set incorrect by the peer\n"); 206 return CURLE_REMOTE_ACCESS_DENIED; 207 } 208 209 ntlm->target_info = malloc(target_info_len); 210 if(!ntlm->target_info) 211 return CURLE_OUT_OF_MEMORY; 212 213 memcpy(ntlm->target_info, &buffer[target_info_offset], target_info_len); 214 ntlm->target_info_len = target_info_len; 215 216 } 217 218 } 219 220 return CURLE_OK; 221} 222 223#endif 224 225/* 226 NTLM message structure notes: 227 228 A 'short' is a 'network short', a little-endian 16-bit unsigned value. 229 230 A 'long' is a 'network long', a little-endian, 32-bit unsigned value. 231 232 A 'security buffer' represents a triplet used to point to a buffer, 233 consisting of two shorts and one long: 234 235 1. A 'short' containing the length of the buffer content in bytes. 236 2. A 'short' containing the allocated space for the buffer in bytes. 237 3. A 'long' containing the offset to the start of the buffer in bytes, 238 from the beginning of the NTLM message. 239*/ 240 241/* 242 * Curl_ntlm_decode_type2_message() 243 * 244 * This is used to decode a ntlm type-2 message received from a HTTP or SASL 245 * based (such as SMTP, POP3 or IMAP) server. The message is first decoded 246 * from a base64 string into a raw ntlm message and checked for validity 247 * before the appropriate data for creating a type-3 message is written to 248 * the given ntlm data structure. 249 * 250 * Parameters: 251 * 252 * data [in] - Pointer to session handle. 253 * header [in] - Pointer to the input buffer. 254 * ntlm [in] - Pointer to ntlm data struct being used and modified. 255 * 256 * Returns CURLE_OK on success. 257 */ 258CURLcode Curl_ntlm_decode_type2_message(struct SessionHandle *data, 259 const char *header, 260 struct ntlmdata *ntlm) 261{ 262#ifndef USE_WINDOWS_SSPI 263 static const char type2_marker[] = { 0x02, 0x00, 0x00, 0x00 }; 264#endif 265 266 /* NTLM type-2 message structure: 267 268 Index Description Content 269 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP" 270 (0x4e544c4d53535000) 271 8 NTLM Message Type long (0x02000000) 272 12 Target Name security buffer 273 20 Flags long 274 24 Challenge 8 bytes 275 (32) Context 8 bytes (two consecutive longs) (*) 276 (40) Target Information security buffer (*) 277 (48) OS Version Structure 8 bytes (*) 278 32 (48) (56) Start of data block (*) 279 (*) -> Optional 280 */ 281 282 size_t size = 0; 283 unsigned char *buffer = NULL; 284 CURLcode error; 285 286#if defined(CURL_DISABLE_VERBOSE_STRINGS) || defined(USE_WINDOWS_SSPI) 287 (void)data; 288#endif 289 290 error = Curl_base64_decode(header, &buffer, &size); 291 if(error) 292 return error; 293 294 if(!buffer) { 295 infof(data, "NTLM handshake failure (unhandled condition)\n"); 296 return CURLE_REMOTE_ACCESS_DENIED; 297 } 298 299#ifdef USE_WINDOWS_SSPI 300 ntlm->type_2 = malloc(size + 1); 301 if(ntlm->type_2 == NULL) { 302 free(buffer); 303 return CURLE_OUT_OF_MEMORY; 304 } 305 ntlm->n_type_2 = curlx_uztoul(size); 306 memcpy(ntlm->type_2, buffer, size); 307#else 308 ntlm->flags = 0; 309 310 if((size < 32) || 311 (memcmp(buffer, NTLMSSP_SIGNATURE, 8) != 0) || 312 (memcmp(buffer + 8, type2_marker, sizeof(type2_marker)) != 0)) { 313 /* This was not a good enough type-2 message */ 314 free(buffer); 315 infof(data, "NTLM handshake failure (bad type-2 message)\n"); 316 return CURLE_REMOTE_ACCESS_DENIED; 317 } 318 319 ntlm->flags = readint_le(&buffer[20]); 320 memcpy(ntlm->nonce, &buffer[24], 8); 321 322 if(ntlm->flags & NTLMFLAG_NEGOTIATE_TARGET_INFO) { 323 error = Curl_ntlm_decode_type2_target(data, buffer, size, ntlm); 324 if(error) { 325 free(buffer); 326 infof(data, "NTLM handshake failure (bad type-2 message)\n"); 327 return error; 328 } 329 } 330 331 DEBUG_OUT({ 332 fprintf(stderr, "**** TYPE2 header flags=0x%08.8lx ", ntlm->flags); 333 ntlm_print_flags(stderr, ntlm->flags); 334 fprintf(stderr, "\n nonce="); 335 ntlm_print_hex(stderr, (char *)ntlm->nonce, 8); 336 fprintf(stderr, "\n****\n"); 337 fprintf(stderr, "**** Header %s\n ", header); 338 }); 339#endif 340 free(buffer); 341 342 return CURLE_OK; 343} 344 345#ifdef USE_WINDOWS_SSPI 346void Curl_ntlm_sspi_cleanup(struct ntlmdata *ntlm) 347{ 348 Curl_safefree(ntlm->type_2); 349 if(ntlm->has_handles) { 350 s_pSecFn->DeleteSecurityContext(&ntlm->c_handle); 351 s_pSecFn->FreeCredentialsHandle(&ntlm->handle); 352 ntlm->has_handles = 0; 353 } 354 if(ntlm->p_identity) { 355 Curl_safefree(ntlm->identity.User); 356 Curl_safefree(ntlm->identity.Password); 357 Curl_safefree(ntlm->identity.Domain); 358 ntlm->p_identity = NULL; 359 } 360} 361#endif 362 363#ifndef USE_WINDOWS_SSPI 364/* copy the source to the destination and fill in zeroes in every 365 other destination byte! */ 366static void unicodecpy(unsigned char *dest, const char *src, size_t length) 367{ 368 size_t i; 369 for(i = 0; i < length; i++) { 370 dest[2 * i] = (unsigned char)src[i]; 371 dest[2 * i + 1] = '\0'; 372 } 373} 374#endif 375 376/* 377 * Curl_ntlm_create_type1_message() 378 * 379 * This is used to generate an already encoded NTLM type-1 message ready for 380 * sending to the recipient, be it a HTTP or SASL based (such as SMTP, POP3 381 * or IMAP) server, using the appropriate compile time crypo API. 382 * 383 * Parameters: 384 * 385 * userp [in] - The user name in the format User or Domain\User. 386 * passdwp [in] - The user's password. 387 * ntlm [in/out] - The ntlm data struct being used and modified. 388 * outptr [in/out] - The address where a pointer to newly allocated memory 389 * holding the result will be stored upon completion. 390 * outlen [out] - The length of the output message. 391 * 392 * Returns CURLE_OK on success. 393 */ 394CURLcode Curl_ntlm_create_type1_message(const char *userp, 395 const char *passwdp, 396 struct ntlmdata *ntlm, 397 char **outptr, 398 size_t *outlen) 399{ 400 /* NTLM type-1 message structure: 401 402 Index Description Content 403 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP" 404 (0x4e544c4d53535000) 405 8 NTLM Message Type long (0x01000000) 406 12 Flags long 407 (16) Supplied Domain security buffer (*) 408 (24) Supplied Workstation security buffer (*) 409 (32) OS Version Structure 8 bytes (*) 410 (32) (40) Start of data block (*) 411 (*) -> Optional 412 */ 413 414 unsigned char ntlmbuf[NTLM_BUFSIZE]; 415 size_t size; 416 417#ifdef USE_WINDOWS_SSPI 418 419 SecBuffer buf; 420 SecBufferDesc desc; 421 SECURITY_STATUS status; 422 unsigned long attrs; 423 xcharp_u useranddomain; 424 xcharp_u user, dup_user; 425 xcharp_u domain, dup_domain; 426 xcharp_u passwd, dup_passwd; 427 size_t domlen = 0; 428 TimeStamp tsDummy; /* For Windows 9x compatibility of SSPI calls */ 429 430 domain.const_tchar_ptr = TEXT(""); 431 432 Curl_ntlm_sspi_cleanup(ntlm); 433 434 if(userp && *userp) { 435 436 /* null initialize ntlm identity's data to allow proper cleanup */ 437 ntlm->p_identity = &ntlm->identity; 438 memset(ntlm->p_identity, 0, sizeof(*ntlm->p_identity)); 439 440 useranddomain.tchar_ptr = Curl_convert_UTF8_to_tchar((char *)userp); 441 if(!useranddomain.tchar_ptr) 442 return CURLE_OUT_OF_MEMORY; 443 444 user.const_tchar_ptr = _tcschr(useranddomain.const_tchar_ptr, TEXT('\\')); 445 if(!user.const_tchar_ptr) 446 user.const_tchar_ptr = _tcschr(useranddomain.const_tchar_ptr, TEXT('/')); 447 448 if(user.tchar_ptr) { 449 domain.tchar_ptr = useranddomain.tchar_ptr; 450 domlen = user.tchar_ptr - useranddomain.tchar_ptr; 451 user.tchar_ptr++; 452 } 453 else { 454 user.tchar_ptr = useranddomain.tchar_ptr; 455 domain.const_tchar_ptr = TEXT(""); 456 domlen = 0; 457 } 458 459 /* setup ntlm identity's user and length */ 460 dup_user.tchar_ptr = _tcsdup(user.tchar_ptr); 461 if(!dup_user.tchar_ptr) { 462 Curl_unicodefree(useranddomain.tchar_ptr); 463 return CURLE_OUT_OF_MEMORY; 464 } 465 ntlm->identity.User = dup_user.tbyte_ptr; 466 ntlm->identity.UserLength = curlx_uztoul(_tcslen(dup_user.tchar_ptr)); 467 dup_user.tchar_ptr = NULL; 468 469 /* setup ntlm identity's domain and length */ 470 dup_domain.tchar_ptr = malloc(sizeof(TCHAR) * (domlen + 1)); 471 if(!dup_domain.tchar_ptr) { 472 Curl_unicodefree(useranddomain.tchar_ptr); 473 return CURLE_OUT_OF_MEMORY; 474 } 475 _tcsncpy(dup_domain.tchar_ptr, domain.tchar_ptr, domlen); 476 *(dup_domain.tchar_ptr + domlen) = TEXT('\0'); 477 ntlm->identity.Domain = dup_domain.tbyte_ptr; 478 ntlm->identity.DomainLength = curlx_uztoul(domlen); 479 dup_domain.tchar_ptr = NULL; 480 481 Curl_unicodefree(useranddomain.tchar_ptr); 482 483 /* setup ntlm identity's password and length */ 484 passwd.tchar_ptr = Curl_convert_UTF8_to_tchar((char *)passwdp); 485 if(!passwd.tchar_ptr) 486 return CURLE_OUT_OF_MEMORY; 487 dup_passwd.tchar_ptr = _tcsdup(passwd.tchar_ptr); 488 if(!dup_passwd.tchar_ptr) { 489 Curl_unicodefree(passwd.tchar_ptr); 490 return CURLE_OUT_OF_MEMORY; 491 } 492 ntlm->identity.Password = dup_passwd.tbyte_ptr; 493 ntlm->identity.PasswordLength = 494 curlx_uztoul(_tcslen(dup_passwd.tchar_ptr)); 495 dup_passwd.tchar_ptr = NULL; 496 497 Curl_unicodefree(passwd.tchar_ptr); 498 499 /* setup ntlm identity's flags */ 500 ntlm->identity.Flags = SECFLAG_WINNT_AUTH_IDENTITY; 501 } 502 else 503 ntlm->p_identity = NULL; 504 505 status = s_pSecFn->AcquireCredentialsHandle(NULL, 506 (TCHAR *) TEXT("NTLM"), 507 SECPKG_CRED_OUTBOUND, NULL, 508 ntlm->p_identity, NULL, NULL, 509 &ntlm->handle, &tsDummy); 510 if(status != SEC_E_OK) 511 return CURLE_OUT_OF_MEMORY; 512 513 desc.ulVersion = SECBUFFER_VERSION; 514 desc.cBuffers = 1; 515 desc.pBuffers = &buf; 516 buf.cbBuffer = NTLM_BUFSIZE; 517 buf.BufferType = SECBUFFER_TOKEN; 518 buf.pvBuffer = ntlmbuf; 519 520 status = s_pSecFn->InitializeSecurityContext(&ntlm->handle, NULL, 521 (TCHAR *) TEXT(""), 522 ISC_REQ_CONFIDENTIALITY | 523 ISC_REQ_REPLAY_DETECT | 524 ISC_REQ_CONNECTION, 525 0, SECURITY_NETWORK_DREP, 526 NULL, 0, 527 &ntlm->c_handle, &desc, 528 &attrs, &tsDummy); 529 530 if(status == SEC_I_COMPLETE_AND_CONTINUE || 531 status == SEC_I_CONTINUE_NEEDED) 532 s_pSecFn->CompleteAuthToken(&ntlm->c_handle, &desc); 533 else if(status != SEC_E_OK) { 534 s_pSecFn->FreeCredentialsHandle(&ntlm->handle); 535 return CURLE_RECV_ERROR; 536 } 537 538 ntlm->has_handles = 1; 539 size = buf.cbBuffer; 540 541#else 542 543 const char *host = ""; /* empty */ 544 const char *domain = ""; /* empty */ 545 size_t hostlen = 0; 546 size_t domlen = 0; 547 size_t hostoff = 0; 548 size_t domoff = hostoff + hostlen; /* This is 0: remember that host and 549 domain are empty */ 550 (void)userp; 551 (void)passwdp; 552 (void)ntlm; 553 554#if USE_NTLM2SESSION 555#define NTLM2FLAG NTLMFLAG_NEGOTIATE_NTLM2_KEY 556#else 557#define NTLM2FLAG 0 558#endif 559 snprintf((char *)ntlmbuf, NTLM_BUFSIZE, 560 NTLMSSP_SIGNATURE "%c" 561 "\x01%c%c%c" /* 32-bit type = 1 */ 562 "%c%c%c%c" /* 32-bit NTLM flag field */ 563 "%c%c" /* domain length */ 564 "%c%c" /* domain allocated space */ 565 "%c%c" /* domain name offset */ 566 "%c%c" /* 2 zeroes */ 567 "%c%c" /* host length */ 568 "%c%c" /* host allocated space */ 569 "%c%c" /* host name offset */ 570 "%c%c" /* 2 zeroes */ 571 "%s" /* host name */ 572 "%s", /* domain string */ 573 0, /* trailing zero */ 574 0, 0, 0, /* part of type-1 long */ 575 576 LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM | 577 NTLMFLAG_REQUEST_TARGET | 578 NTLMFLAG_NEGOTIATE_NTLM_KEY | 579 NTLM2FLAG | 580 NTLMFLAG_NEGOTIATE_ALWAYS_SIGN), 581 SHORTPAIR(domlen), 582 SHORTPAIR(domlen), 583 SHORTPAIR(domoff), 584 0, 0, 585 SHORTPAIR(hostlen), 586 SHORTPAIR(hostlen), 587 SHORTPAIR(hostoff), 588 0, 0, 589 host, /* this is empty */ 590 domain /* this is empty */); 591 592 /* Initial packet length */ 593 size = 32 + hostlen + domlen; 594 595#endif 596 597 DEBUG_OUT({ 598 fprintf(stderr, "* TYPE1 header flags=0x%02.2x%02.2x%02.2x%02.2x " 599 "0x%08.8x ", 600 LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM | 601 NTLMFLAG_REQUEST_TARGET | 602 NTLMFLAG_NEGOTIATE_NTLM_KEY | 603 NTLM2FLAG | 604 NTLMFLAG_NEGOTIATE_ALWAYS_SIGN), 605 NTLMFLAG_NEGOTIATE_OEM | 606 NTLMFLAG_REQUEST_TARGET | 607 NTLMFLAG_NEGOTIATE_NTLM_KEY | 608 NTLM2FLAG | 609 NTLMFLAG_NEGOTIATE_ALWAYS_SIGN); 610 ntlm_print_flags(stderr, 611 NTLMFLAG_NEGOTIATE_OEM | 612 NTLMFLAG_REQUEST_TARGET | 613 NTLMFLAG_NEGOTIATE_NTLM_KEY | 614 NTLM2FLAG | 615 NTLMFLAG_NEGOTIATE_ALWAYS_SIGN); 616 fprintf(stderr, "\n****\n"); 617 }); 618 619 /* Return with binary blob encoded into base64 */ 620 return Curl_base64_encode(NULL, (char *)ntlmbuf, size, outptr, outlen); 621} 622 623/* 624 * Curl_ntlm_create_type3_message() 625 * 626 * This is used to generate an already encoded NTLM type-3 message ready for 627 * sending to the recipient, be it a HTTP or SASL based (such as SMTP, POP3 628 * or IMAP) server, using the appropriate compile time crypo API. 629 * 630 * Parameters: 631 * 632 * data [in] - The session handle. 633 * userp [in] - The user name in the format User or Domain\User. 634 * passdwp [in] - The user's password. 635 * ntlm [in/out] - The ntlm data struct being used and modified. 636 * outptr [in/out] - The address where a pointer to newly allocated memory 637 * holding the result will be stored upon completion. 638 * outlen [out] - The length of the output message. 639 * 640 * Returns CURLE_OK on success. 641 */ 642CURLcode Curl_ntlm_create_type3_message(struct SessionHandle *data, 643 const char *userp, 644 const char *passwdp, 645 struct ntlmdata *ntlm, 646 char **outptr, 647 size_t *outlen) 648{ 649 /* NTLM type-3 message structure: 650 651 Index Description Content 652 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP" 653 (0x4e544c4d53535000) 654 8 NTLM Message Type long (0x03000000) 655 12 LM/LMv2 Response security buffer 656 20 NTLM/NTLMv2 Response security buffer 657 28 Target Name security buffer 658 36 User Name security buffer 659 44 Workstation Name security buffer 660 (52) Session Key security buffer (*) 661 (60) Flags long (*) 662 (64) OS Version Structure 8 bytes (*) 663 52 (64) (72) Start of data block 664 (*) -> Optional 665 */ 666 667 unsigned char ntlmbuf[NTLM_BUFSIZE]; 668 size_t size; 669 670#ifdef USE_WINDOWS_SSPI 671 SecBuffer type_2; 672 SecBuffer type_3; 673 SecBufferDesc type_2_desc; 674 SecBufferDesc type_3_desc; 675 SECURITY_STATUS status; 676 unsigned long attrs; 677 TimeStamp tsDummy; /* For Windows 9x compatibility of SSPI calls */ 678 679 (void)passwdp; 680 (void)userp; 681 (void)data; 682 683 type_2_desc.ulVersion = type_3_desc.ulVersion = SECBUFFER_VERSION; 684 type_2_desc.cBuffers = type_3_desc.cBuffers = 1; 685 type_2_desc.pBuffers = &type_2; 686 type_3_desc.pBuffers = &type_3; 687 688 type_2.BufferType = SECBUFFER_TOKEN; 689 type_2.pvBuffer = ntlm->type_2; 690 type_2.cbBuffer = ntlm->n_type_2; 691 type_3.BufferType = SECBUFFER_TOKEN; 692 type_3.pvBuffer = ntlmbuf; 693 type_3.cbBuffer = NTLM_BUFSIZE; 694 695 status = s_pSecFn->InitializeSecurityContext(&ntlm->handle, 696 &ntlm->c_handle, 697 (TCHAR *) TEXT(""), 698 ISC_REQ_CONFIDENTIALITY | 699 ISC_REQ_REPLAY_DETECT | 700 ISC_REQ_CONNECTION, 701 0, SECURITY_NETWORK_DREP, 702 &type_2_desc, 703 0, &ntlm->c_handle, 704 &type_3_desc, 705 &attrs, &tsDummy); 706 if(status != SEC_E_OK) 707 return CURLE_RECV_ERROR; 708 709 size = type_3.cbBuffer; 710 711 Curl_ntlm_sspi_cleanup(ntlm); 712 713#else 714 int lmrespoff; 715 unsigned char lmresp[24]; /* fixed-size */ 716#if USE_NTRESPONSES 717 int ntrespoff; 718 unsigned int ntresplen = 24; 719 unsigned char ntresp[24]; /* fixed-size */ 720 unsigned char *ptr_ntresp = &ntresp[0]; 721 unsigned char *ntlmv2resp = NULL; 722#endif 723 bool unicode = (ntlm->flags & NTLMFLAG_NEGOTIATE_UNICODE) ? TRUE : FALSE; 724 char host[HOSTNAME_MAX + 1] = ""; 725 const char *user; 726 const char *domain = ""; 727 size_t hostoff = 0; 728 size_t useroff = 0; 729 size_t domoff = 0; 730 size_t hostlen = 0; 731 size_t userlen = 0; 732 size_t domlen = 0; 733 CURLcode res = CURLE_OK; 734 735 user = strchr(userp, '\\'); 736 if(!user) 737 user = strchr(userp, '/'); 738 739 if(user) { 740 domain = userp; 741 domlen = (user - domain); 742 user++; 743 } 744 else 745 user = userp; 746 747 if(user) 748 userlen = strlen(user); 749 750 /* Get the machine's un-qualified host name as NTLM doesn't like the fully 751 qualified domain name */ 752 if(Curl_gethostname(host, sizeof(host))) { 753 infof(data, "gethostname() failed, continuing without!\n"); 754 hostlen = 0; 755 } 756 else { 757 hostlen = strlen(host); 758 } 759 760#if USE_NTRESPONSES 761 if(ntlm->target_info_len) { 762 unsigned char ntbuffer[0x18]; 763 unsigned char entropy[8]; 764 unsigned char ntlmv2hash[0x18]; 765 766#if defined(DEBUGBUILD) 767 /* Use static client nonce in debug (Test Suite) builds */ 768 memcpy(entropy, "12345678", sizeof(entropy)); 769#else 770 /* Create an 8 byte random client nonce */ 771 Curl_ssl_random(data, entropy, sizeof(entropy)); 772#endif 773 774 res = Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer); 775 if(res) 776 return res; 777 778 res = Curl_ntlm_core_mk_ntlmv2_hash(user, userlen, domain, domlen, 779 ntbuffer, ntlmv2hash); 780 if(res) 781 return res; 782 783 /* LMv2 response */ 784 res = Curl_ntlm_core_mk_lmv2_resp(ntlmv2hash, entropy, &ntlm->nonce[0], 785 lmresp); 786 if(res) 787 return res; 788 789 /* NTLMv2 response */ 790 res = Curl_ntlm_core_mk_ntlmv2_resp(ntlmv2hash, entropy, ntlm, &ntlmv2resp, 791 &ntresplen); 792 if(res) 793 return res; 794 795 ptr_ntresp = ntlmv2resp; 796 } 797 else 798#endif 799 800#if USE_NTLM2SESSION 801 /* We don't support NTLM2 if we don't have USE_NTRESPONSES */ 802 if(ntlm->flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) { 803 unsigned char ntbuffer[0x18]; 804 unsigned char tmp[0x18]; 805 unsigned char md5sum[MD5_DIGEST_LENGTH]; 806 unsigned char entropy[8]; 807 808 /* Need to create 8 bytes random data */ 809 Curl_ssl_random(data, entropy, sizeof(entropy)); 810 811 /* 8 bytes random data as challenge in lmresp */ 812 memcpy(lmresp, entropy, 8); 813 814 /* Pad with zeros */ 815 memset(lmresp + 8, 0, 0x10); 816 817 /* Fill tmp with challenge(nonce?) + entropy */ 818 memcpy(tmp, &ntlm->nonce[0], 8); 819 memcpy(tmp + 8, entropy, 8); 820 821 Curl_ssl_md5sum(tmp, 16, md5sum, MD5_DIGEST_LENGTH); 822 823 /* We shall only use the first 8 bytes of md5sum, but the des 824 code in Curl_ntlm_core_lm_resp only encrypt the first 8 bytes */ 825 if(CURLE_OUT_OF_MEMORY == 826 Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer)) 827 return CURLE_OUT_OF_MEMORY; 828 829 Curl_ntlm_core_lm_resp(ntbuffer, md5sum, ntresp); 830 831 /* End of NTLM2 Session code */ 832 833 } 834 else 835#endif 836 { 837 838#if USE_NTRESPONSES 839 unsigned char ntbuffer[0x18]; 840#endif 841 unsigned char lmbuffer[0x18]; 842 843#if USE_NTRESPONSES 844 if(CURLE_OUT_OF_MEMORY == 845 Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer)) 846 return CURLE_OUT_OF_MEMORY; 847 Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], ntresp); 848#endif 849 850 Curl_ntlm_core_mk_lm_hash(data, passwdp, lmbuffer); 851 Curl_ntlm_core_lm_resp(lmbuffer, &ntlm->nonce[0], lmresp); 852 /* A safer but less compatible alternative is: 853 * Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], lmresp); 854 * See http://davenport.sourceforge.net/ntlm.html#ntlmVersion2 */ 855 } 856 857 if(unicode) { 858 domlen = domlen * 2; 859 userlen = userlen * 2; 860 hostlen = hostlen * 2; 861 } 862 863 lmrespoff = 64; /* size of the message header */ 864#if USE_NTRESPONSES 865 ntrespoff = lmrespoff + 0x18; 866 domoff = ntrespoff + ntresplen; 867#else 868 domoff = lmrespoff + 0x18; 869#endif 870 useroff = domoff + domlen; 871 hostoff = useroff + userlen; 872 873 /* Create the big type-3 message binary blob */ 874 size = snprintf((char *)ntlmbuf, NTLM_BUFSIZE, 875 NTLMSSP_SIGNATURE "%c" 876 "\x03%c%c%c" /* 32-bit type = 3 */ 877 878 "%c%c" /* LanManager length */ 879 "%c%c" /* LanManager allocated space */ 880 "%c%c" /* LanManager offset */ 881 "%c%c" /* 2 zeroes */ 882 883 "%c%c" /* NT-response length */ 884 "%c%c" /* NT-response allocated space */ 885 "%c%c" /* NT-response offset */ 886 "%c%c" /* 2 zeroes */ 887 888 "%c%c" /* domain length */ 889 "%c%c" /* domain allocated space */ 890 "%c%c" /* domain name offset */ 891 "%c%c" /* 2 zeroes */ 892 893 "%c%c" /* user length */ 894 "%c%c" /* user allocated space */ 895 "%c%c" /* user offset */ 896 "%c%c" /* 2 zeroes */ 897 898 "%c%c" /* host length */ 899 "%c%c" /* host allocated space */ 900 "%c%c" /* host offset */ 901 "%c%c" /* 2 zeroes */ 902 903 "%c%c" /* session key length (unknown purpose) */ 904 "%c%c" /* session key allocated space (unknown purpose) */ 905 "%c%c" /* session key offset (unknown purpose) */ 906 "%c%c" /* 2 zeroes */ 907 908 "%c%c%c%c", /* flags */ 909 910 /* domain string */ 911 /* user string */ 912 /* host string */ 913 /* LanManager response */ 914 /* NT response */ 915 916 0, /* zero termination */ 917 0, 0, 0, /* type-3 long, the 24 upper bits */ 918 919 SHORTPAIR(0x18), /* LanManager response length, twice */ 920 SHORTPAIR(0x18), 921 SHORTPAIR(lmrespoff), 922 0x0, 0x0, 923 924#if USE_NTRESPONSES 925 SHORTPAIR(ntresplen), /* NT-response length, twice */ 926 SHORTPAIR(ntresplen), 927 SHORTPAIR(ntrespoff), 928 0x0, 0x0, 929#else 930 0x0, 0x0, 931 0x0, 0x0, 932 0x0, 0x0, 933 0x0, 0x0, 934#endif 935 SHORTPAIR(domlen), 936 SHORTPAIR(domlen), 937 SHORTPAIR(domoff), 938 0x0, 0x0, 939 940 SHORTPAIR(userlen), 941 SHORTPAIR(userlen), 942 SHORTPAIR(useroff), 943 0x0, 0x0, 944 945 SHORTPAIR(hostlen), 946 SHORTPAIR(hostlen), 947 SHORTPAIR(hostoff), 948 0x0, 0x0, 949 950 0x0, 0x0, 951 0x0, 0x0, 952 0x0, 0x0, 953 0x0, 0x0, 954 955 LONGQUARTET(ntlm->flags)); 956 957 DEBUGASSERT(size == 64); 958 DEBUGASSERT(size == (size_t)lmrespoff); 959 960 /* We append the binary hashes */ 961 if(size < (NTLM_BUFSIZE - 0x18)) { 962 memcpy(&ntlmbuf[size], lmresp, 0x18); 963 size += 0x18; 964 } 965 966 DEBUG_OUT({ 967 fprintf(stderr, "**** TYPE3 header lmresp="); 968 ntlm_print_hex(stderr, (char *)&ntlmbuf[lmrespoff], 0x18); 969 }); 970 971#if USE_NTRESPONSES 972 if(size < (NTLM_BUFSIZE - ntresplen)) { 973 DEBUGASSERT(size == (size_t)ntrespoff); 974 memcpy(&ntlmbuf[size], ptr_ntresp, ntresplen); 975 size += ntresplen; 976 } 977 978 DEBUG_OUT({ 979 fprintf(stderr, "\n ntresp="); 980 ntlm_print_hex(stderr, (char *)&ntlmbuf[ntrespoff], ntresplen); 981 }); 982 983 Curl_safefree(ntlmv2resp);/* Free the dynamic buffer allocated for NTLMv2 */ 984 985#endif 986 987 DEBUG_OUT({ 988 fprintf(stderr, "\n flags=0x%02.2x%02.2x%02.2x%02.2x 0x%08.8x ", 989 LONGQUARTET(ntlm->flags), ntlm->flags); 990 ntlm_print_flags(stderr, ntlm->flags); 991 fprintf(stderr, "\n****\n"); 992 }); 993 994 /* Make sure that the domain, user and host strings fit in the 995 buffer before we copy them there. */ 996 if(size + userlen + domlen + hostlen >= NTLM_BUFSIZE) { 997 failf(data, "user + domain + host name too big"); 998 return CURLE_OUT_OF_MEMORY; 999 } 1000 1001 DEBUGASSERT(size == domoff); 1002 if(unicode) 1003 unicodecpy(&ntlmbuf[size], domain, domlen / 2); 1004 else 1005 memcpy(&ntlmbuf[size], domain, domlen); 1006 1007 size += domlen; 1008 1009 DEBUGASSERT(size == useroff); 1010 if(unicode) 1011 unicodecpy(&ntlmbuf[size], user, userlen / 2); 1012 else 1013 memcpy(&ntlmbuf[size], user, userlen); 1014 1015 size += userlen; 1016 1017 DEBUGASSERT(size == hostoff); 1018 if(unicode) 1019 unicodecpy(&ntlmbuf[size], host, hostlen / 2); 1020 else 1021 memcpy(&ntlmbuf[size], host, hostlen); 1022 1023 size += hostlen; 1024 1025 /* Convert domain, user, and host to ASCII but leave the rest as-is */ 1026 res = Curl_convert_to_network(data, (char *)&ntlmbuf[domoff], 1027 size - domoff); 1028 if(res) 1029 return CURLE_CONV_FAILED; 1030 1031#endif 1032 1033 /* Return with binary blob encoded into base64 */ 1034 return Curl_base64_encode(NULL, (char *)ntlmbuf, size, outptr, outlen); 1035} 1036 1037#endif /* USE_NTLM */ 1038