1/*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 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 https://curl.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 * SPDX-License-Identifier: curl 22 * 23 ***************************************************************************/ 24 25#include "curl_setup.h" 26 27#if defined(USE_NTLM) && !defined(USE_WINDOWS_SSPI) 28 29/* 30 * NTLM details: 31 * 32 * https://davenport.sourceforge.net/ntlm.html 33 * https://www.innovation.ch/java/ntlm.html 34 */ 35 36#define DEBUG_ME 0 37 38#include "urldata.h" 39#include "sendf.h" 40#include "curl_ntlm_core.h" 41#include "curl_gethostname.h" 42#include "curl_multibyte.h" 43#include "curl_md5.h" 44#include "warnless.h" 45#include "rand.h" 46#include "vtls/vtls.h" 47#include "strdup.h" 48 49#define BUILDING_CURL_NTLM_MSGS_C 50#include "vauth/vauth.h" 51#include "vauth/ntlm.h" 52#include "curl_endian.h" 53#include "curl_printf.h" 54 55/* The last #include files should be: */ 56#include "curl_memory.h" 57#include "memdebug.h" 58 59/* "NTLMSSP" signature is always in ASCII regardless of the platform */ 60#define NTLMSSP_SIGNATURE "\x4e\x54\x4c\x4d\x53\x53\x50" 61 62/* The fixed host name we provide, in order to not leak our real local host 63 name. Copy the name used by Firefox. */ 64#define NTLM_HOSTNAME "WORKSTATION" 65 66#if DEBUG_ME 67# define DEBUG_OUT(x) x 68static void ntlm_print_flags(FILE *handle, unsigned long flags) 69{ 70 if(flags & NTLMFLAG_NEGOTIATE_UNICODE) 71 fprintf(handle, "NTLMFLAG_NEGOTIATE_UNICODE "); 72 if(flags & NTLMFLAG_NEGOTIATE_OEM) 73 fprintf(handle, "NTLMFLAG_NEGOTIATE_OEM "); 74 if(flags & NTLMFLAG_REQUEST_TARGET) 75 fprintf(handle, "NTLMFLAG_REQUEST_TARGET "); 76 if(flags & (1<<3)) 77 fprintf(handle, "NTLMFLAG_UNKNOWN_3 "); 78 if(flags & NTLMFLAG_NEGOTIATE_SIGN) 79 fprintf(handle, "NTLMFLAG_NEGOTIATE_SIGN "); 80 if(flags & NTLMFLAG_NEGOTIATE_SEAL) 81 fprintf(handle, "NTLMFLAG_NEGOTIATE_SEAL "); 82 if(flags & NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE) 83 fprintf(handle, "NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE "); 84 if(flags & NTLMFLAG_NEGOTIATE_LM_KEY) 85 fprintf(handle, "NTLMFLAG_NEGOTIATE_LM_KEY "); 86 if(flags & NTLMFLAG_NEGOTIATE_NTLM_KEY) 87 fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM_KEY "); 88 if(flags & (1<<10)) 89 fprintf(handle, "NTLMFLAG_UNKNOWN_10 "); 90 if(flags & NTLMFLAG_NEGOTIATE_ANONYMOUS) 91 fprintf(handle, "NTLMFLAG_NEGOTIATE_ANONYMOUS "); 92 if(flags & NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED) 93 fprintf(handle, "NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED "); 94 if(flags & NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED) 95 fprintf(handle, "NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED "); 96 if(flags & NTLMFLAG_NEGOTIATE_LOCAL_CALL) 97 fprintf(handle, "NTLMFLAG_NEGOTIATE_LOCAL_CALL "); 98 if(flags & NTLMFLAG_NEGOTIATE_ALWAYS_SIGN) 99 fprintf(handle, "NTLMFLAG_NEGOTIATE_ALWAYS_SIGN "); 100 if(flags & NTLMFLAG_TARGET_TYPE_DOMAIN) 101 fprintf(handle, "NTLMFLAG_TARGET_TYPE_DOMAIN "); 102 if(flags & NTLMFLAG_TARGET_TYPE_SERVER) 103 fprintf(handle, "NTLMFLAG_TARGET_TYPE_SERVER "); 104 if(flags & NTLMFLAG_TARGET_TYPE_SHARE) 105 fprintf(handle, "NTLMFLAG_TARGET_TYPE_SHARE "); 106 if(flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) 107 fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM2_KEY "); 108 if(flags & NTLMFLAG_REQUEST_INIT_RESPONSE) 109 fprintf(handle, "NTLMFLAG_REQUEST_INIT_RESPONSE "); 110 if(flags & NTLMFLAG_REQUEST_ACCEPT_RESPONSE) 111 fprintf(handle, "NTLMFLAG_REQUEST_ACCEPT_RESPONSE "); 112 if(flags & NTLMFLAG_REQUEST_NONNT_SESSION_KEY) 113 fprintf(handle, "NTLMFLAG_REQUEST_NONNT_SESSION_KEY "); 114 if(flags & NTLMFLAG_NEGOTIATE_TARGET_INFO) 115 fprintf(handle, "NTLMFLAG_NEGOTIATE_TARGET_INFO "); 116 if(flags & (1<<24)) 117 fprintf(handle, "NTLMFLAG_UNKNOWN_24 "); 118 if(flags & (1<<25)) 119 fprintf(handle, "NTLMFLAG_UNKNOWN_25 "); 120 if(flags & (1<<26)) 121 fprintf(handle, "NTLMFLAG_UNKNOWN_26 "); 122 if(flags & (1<<27)) 123 fprintf(handle, "NTLMFLAG_UNKNOWN_27 "); 124 if(flags & (1<<28)) 125 fprintf(handle, "NTLMFLAG_UNKNOWN_28 "); 126 if(flags & NTLMFLAG_NEGOTIATE_128) 127 fprintf(handle, "NTLMFLAG_NEGOTIATE_128 "); 128 if(flags & NTLMFLAG_NEGOTIATE_KEY_EXCHANGE) 129 fprintf(handle, "NTLMFLAG_NEGOTIATE_KEY_EXCHANGE "); 130 if(flags & NTLMFLAG_NEGOTIATE_56) 131 fprintf(handle, "NTLMFLAG_NEGOTIATE_56 "); 132} 133 134static void ntlm_print_hex(FILE *handle, const char *buf, size_t len) 135{ 136 const char *p = buf; 137 138 (void) handle; 139 140 fprintf(stderr, "0x"); 141 while(len-- > 0) 142 fprintf(stderr, "%02.2x", (unsigned int)*p++); 143} 144#else 145# define DEBUG_OUT(x) Curl_nop_stmt 146#endif 147 148/* 149 * ntlm_decode_type2_target() 150 * 151 * This is used to decode the "target info" in the NTLM type-2 message 152 * received. 153 * 154 * Parameters: 155 * 156 * data [in] - The session handle. 157 * type2ref [in] - The type-2 message. 158 * ntlm [in/out] - The NTLM data struct being used and modified. 159 * 160 * Returns CURLE_OK on success. 161 */ 162static CURLcode ntlm_decode_type2_target(struct Curl_easy *data, 163 const struct bufref *type2ref, 164 struct ntlmdata *ntlm) 165{ 166 unsigned short target_info_len = 0; 167 unsigned int target_info_offset = 0; 168 const unsigned char *type2 = Curl_bufref_ptr(type2ref); 169 size_t type2len = Curl_bufref_len(type2ref); 170 171#if defined(CURL_DISABLE_VERBOSE_STRINGS) 172 (void) data; 173#endif 174 175 if(type2len >= 48) { 176 target_info_len = Curl_read16_le(&type2[40]); 177 target_info_offset = Curl_read32_le(&type2[44]); 178 if(target_info_len > 0) { 179 if((target_info_offset > type2len) || 180 (target_info_offset + target_info_len) > type2len || 181 target_info_offset < 48) { 182 infof(data, "NTLM handshake failure (bad type-2 message). " 183 "Target Info Offset Len is set incorrect by the peer"); 184 return CURLE_BAD_CONTENT_ENCODING; 185 } 186 187 free(ntlm->target_info); /* replace any previous data */ 188 ntlm->target_info = Curl_memdup(&type2[target_info_offset], 189 target_info_len); 190 if(!ntlm->target_info) 191 return CURLE_OUT_OF_MEMORY; 192 } 193 } 194 195 ntlm->target_info_len = target_info_len; 196 197 return CURLE_OK; 198} 199 200/* 201 NTLM message structure notes: 202 203 A 'short' is a 'network short', a little-endian 16-bit unsigned value. 204 205 A 'long' is a 'network long', a little-endian, 32-bit unsigned value. 206 207 A 'security buffer' represents a triplet used to point to a buffer, 208 consisting of two shorts and one long: 209 210 1. A 'short' containing the length of the buffer content in bytes. 211 2. A 'short' containing the allocated space for the buffer in bytes. 212 3. A 'long' containing the offset to the start of the buffer in bytes, 213 from the beginning of the NTLM message. 214*/ 215 216/* 217 * Curl_auth_is_ntlm_supported() 218 * 219 * This is used to evaluate if NTLM is supported. 220 * 221 * Parameters: None 222 * 223 * Returns TRUE as NTLM as handled by libcurl. 224 */ 225bool Curl_auth_is_ntlm_supported(void) 226{ 227 return TRUE; 228} 229 230/* 231 * Curl_auth_decode_ntlm_type2_message() 232 * 233 * This is used to decode an NTLM type-2 message. The raw NTLM message is 234 * checked * for validity before the appropriate data for creating a type-3 235 * message is * written to the given NTLM data structure. 236 * 237 * Parameters: 238 * 239 * data [in] - The session handle. 240 * type2ref [in] - The type-2 message. 241 * ntlm [in/out] - The NTLM data struct being used and modified. 242 * 243 * Returns CURLE_OK on success. 244 */ 245CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data, 246 const struct bufref *type2ref, 247 struct ntlmdata *ntlm) 248{ 249 static const char type2_marker[] = { 0x02, 0x00, 0x00, 0x00 }; 250 251 /* NTLM type-2 message structure: 252 253 Index Description Content 254 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP" 255 (0x4e544c4d53535000) 256 8 NTLM Message Type long (0x02000000) 257 12 Target Name security buffer 258 20 Flags long 259 24 Challenge 8 bytes 260 (32) Context 8 bytes (two consecutive longs) (*) 261 (40) Target Information security buffer (*) 262 (48) OS Version Structure 8 bytes (*) 263 32 (48) (56) Start of data block (*) 264 (*) -> Optional 265 */ 266 267 CURLcode result = CURLE_OK; 268 const unsigned char *type2 = Curl_bufref_ptr(type2ref); 269 size_t type2len = Curl_bufref_len(type2ref); 270 271#if defined(CURL_DISABLE_VERBOSE_STRINGS) 272 (void)data; 273#endif 274 275 ntlm->flags = 0; 276 277 if((type2len < 32) || 278 (memcmp(type2, NTLMSSP_SIGNATURE, 8) != 0) || 279 (memcmp(type2 + 8, type2_marker, sizeof(type2_marker)) != 0)) { 280 /* This was not a good enough type-2 message */ 281 infof(data, "NTLM handshake failure (bad type-2 message)"); 282 return CURLE_BAD_CONTENT_ENCODING; 283 } 284 285 ntlm->flags = Curl_read32_le(&type2[20]); 286 memcpy(ntlm->nonce, &type2[24], 8); 287 288 if(ntlm->flags & NTLMFLAG_NEGOTIATE_TARGET_INFO) { 289 result = ntlm_decode_type2_target(data, type2ref, ntlm); 290 if(result) { 291 infof(data, "NTLM handshake failure (bad type-2 message)"); 292 return result; 293 } 294 } 295 296 DEBUG_OUT({ 297 fprintf(stderr, "**** TYPE2 header flags=0x%08.8lx ", ntlm->flags); 298 ntlm_print_flags(stderr, ntlm->flags); 299 fprintf(stderr, "\n nonce="); 300 ntlm_print_hex(stderr, (char *)ntlm->nonce, 8); 301 fprintf(stderr, "\n****\n"); 302 fprintf(stderr, "**** Header %s\n ", header); 303 }); 304 305 return result; 306} 307 308/* copy the source to the destination and fill in zeroes in every 309 other destination byte! */ 310static void unicodecpy(unsigned char *dest, const char *src, size_t length) 311{ 312 size_t i; 313 for(i = 0; i < length; i++) { 314 dest[2 * i] = (unsigned char)src[i]; 315 dest[2 * i + 1] = '\0'; 316 } 317} 318 319/* 320 * Curl_auth_create_ntlm_type1_message() 321 * 322 * This is used to generate an NTLM type-1 message ready for sending to the 323 * recipient using the appropriate compile time crypto API. 324 * 325 * Parameters: 326 * 327 * data [in] - The session handle. 328 * userp [in] - The user name in the format User or Domain\User. 329 * passwdp [in] - The user's password. 330 * service [in] - The service type such as http, smtp, pop or imap. 331 * host [in] - The host name. 332 * ntlm [in/out] - The NTLM data struct being used and modified. 333 * out [out] - The result storage. 334 * 335 * Returns CURLE_OK on success. 336 */ 337CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data, 338 const char *userp, 339 const char *passwdp, 340 const char *service, 341 const char *hostname, 342 struct ntlmdata *ntlm, 343 struct bufref *out) 344{ 345 /* NTLM type-1 message structure: 346 347 Index Description Content 348 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP" 349 (0x4e544c4d53535000) 350 8 NTLM Message Type long (0x01000000) 351 12 Flags long 352 (16) Supplied Domain security buffer (*) 353 (24) Supplied Workstation security buffer (*) 354 (32) OS Version Structure 8 bytes (*) 355 (32) (40) Start of data block (*) 356 (*) -> Optional 357 */ 358 359 size_t size; 360 361 char *ntlmbuf; 362 const char *host = ""; /* empty */ 363 const char *domain = ""; /* empty */ 364 size_t hostlen = 0; 365 size_t domlen = 0; 366 size_t hostoff = 0; 367 size_t domoff = hostoff + hostlen; /* This is 0: remember that host and 368 domain are empty */ 369 (void)data; 370 (void)userp; 371 (void)passwdp; 372 (void)service; 373 (void)hostname; 374 375 /* Clean up any former leftovers and initialise to defaults */ 376 Curl_auth_cleanup_ntlm(ntlm); 377 378 ntlmbuf = aprintf(NTLMSSP_SIGNATURE "%c" 379 "\x01%c%c%c" /* 32-bit type = 1 */ 380 "%c%c%c%c" /* 32-bit NTLM flag field */ 381 "%c%c" /* domain length */ 382 "%c%c" /* domain allocated space */ 383 "%c%c" /* domain name offset */ 384 "%c%c" /* 2 zeroes */ 385 "%c%c" /* host length */ 386 "%c%c" /* host allocated space */ 387 "%c%c" /* host name offset */ 388 "%c%c" /* 2 zeroes */ 389 "%s" /* host name */ 390 "%s", /* domain string */ 391 0, /* trailing zero */ 392 0, 0, 0, /* part of type-1 long */ 393 394 LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM | 395 NTLMFLAG_REQUEST_TARGET | 396 NTLMFLAG_NEGOTIATE_NTLM_KEY | 397 NTLMFLAG_NEGOTIATE_NTLM2_KEY | 398 NTLMFLAG_NEGOTIATE_ALWAYS_SIGN), 399 SHORTPAIR(domlen), 400 SHORTPAIR(domlen), 401 SHORTPAIR(domoff), 402 0, 0, 403 SHORTPAIR(hostlen), 404 SHORTPAIR(hostlen), 405 SHORTPAIR(hostoff), 406 0, 0, 407 host, /* this is empty */ 408 domain /* this is empty */); 409 410 if(!ntlmbuf) 411 return CURLE_OUT_OF_MEMORY; 412 413 /* Initial packet length */ 414 size = 32 + hostlen + domlen; 415 416 DEBUG_OUT({ 417 fprintf(stderr, "* TYPE1 header flags=0x%02.2x%02.2x%02.2x%02.2x " 418 "0x%08.8x ", 419 LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM | 420 NTLMFLAG_REQUEST_TARGET | 421 NTLMFLAG_NEGOTIATE_NTLM_KEY | 422 NTLMFLAG_NEGOTIATE_NTLM2_KEY | 423 NTLMFLAG_NEGOTIATE_ALWAYS_SIGN), 424 NTLMFLAG_NEGOTIATE_OEM | 425 NTLMFLAG_REQUEST_TARGET | 426 NTLMFLAG_NEGOTIATE_NTLM_KEY | 427 NTLMFLAG_NEGOTIATE_NTLM2_KEY | 428 NTLMFLAG_NEGOTIATE_ALWAYS_SIGN); 429 ntlm_print_flags(stderr, 430 NTLMFLAG_NEGOTIATE_OEM | 431 NTLMFLAG_REQUEST_TARGET | 432 NTLMFLAG_NEGOTIATE_NTLM_KEY | 433 NTLMFLAG_NEGOTIATE_NTLM2_KEY | 434 NTLMFLAG_NEGOTIATE_ALWAYS_SIGN); 435 fprintf(stderr, "\n****\n"); 436 }); 437 438 Curl_bufref_set(out, ntlmbuf, size, curl_free); 439 return CURLE_OK; 440} 441 442/* 443 * Curl_auth_create_ntlm_type3_message() 444 * 445 * This is used to generate an already encoded NTLM type-3 message ready for 446 * sending to the recipient using the appropriate compile time crypto API. 447 * 448 * Parameters: 449 * 450 * data [in] - The session handle. 451 * userp [in] - The user name in the format User or Domain\User. 452 * passwdp [in] - The user's password. 453 * ntlm [in/out] - The NTLM data struct being used and modified. 454 * out [out] - The result storage. 455 * 456 * Returns CURLE_OK on success. 457 */ 458CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, 459 const char *userp, 460 const char *passwdp, 461 struct ntlmdata *ntlm, 462 struct bufref *out) 463{ 464 /* NTLM type-3 message structure: 465 466 Index Description Content 467 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP" 468 (0x4e544c4d53535000) 469 8 NTLM Message Type long (0x03000000) 470 12 LM/LMv2 Response security buffer 471 20 NTLM/NTLMv2 Response security buffer 472 28 Target Name security buffer 473 36 User Name security buffer 474 44 Workstation Name security buffer 475 (52) Session Key security buffer (*) 476 (60) Flags long (*) 477 (64) OS Version Structure 8 bytes (*) 478 52 (64) (72) Start of data block 479 (*) -> Optional 480 */ 481 482 CURLcode result = CURLE_OK; 483 size_t size; 484 unsigned char ntlmbuf[NTLM_BUFSIZE]; 485 int lmrespoff; 486 unsigned char lmresp[24]; /* fixed-size */ 487 int ntrespoff; 488 unsigned int ntresplen = 24; 489 unsigned char ntresp[24]; /* fixed-size */ 490 unsigned char *ptr_ntresp = &ntresp[0]; 491 unsigned char *ntlmv2resp = NULL; 492 bool unicode = (ntlm->flags & NTLMFLAG_NEGOTIATE_UNICODE) ? TRUE : FALSE; 493 char host[HOSTNAME_MAX + 1] = ""; 494 const char *user; 495 const char *domain = ""; 496 size_t hostoff = 0; 497 size_t useroff = 0; 498 size_t domoff = 0; 499 size_t hostlen = 0; 500 size_t userlen = 0; 501 size_t domlen = 0; 502 503 memset(lmresp, 0, sizeof(lmresp)); 504 memset(ntresp, 0, sizeof(ntresp)); 505 user = strchr(userp, '\\'); 506 if(!user) 507 user = strchr(userp, '/'); 508 509 if(user) { 510 domain = userp; 511 domlen = (user - domain); 512 user++; 513 } 514 else 515 user = userp; 516 517 userlen = strlen(user); 518 519#ifndef NTLM_HOSTNAME 520 /* Get the machine's un-qualified host name as NTLM doesn't like the fully 521 qualified domain name */ 522 if(Curl_gethostname(host, sizeof(host))) { 523 infof(data, "gethostname() failed, continuing without"); 524 hostlen = 0; 525 } 526 else { 527 hostlen = strlen(host); 528 } 529#else 530 (void)msnprintf(host, sizeof(host), "%s", NTLM_HOSTNAME); 531 hostlen = sizeof(NTLM_HOSTNAME)-1; 532#endif 533 534 if(ntlm->flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) { 535 unsigned char ntbuffer[0x18]; 536 unsigned char entropy[8]; 537 unsigned char ntlmv2hash[0x18]; 538 539 /* Full NTLM version 2 540 Although this cannot be negotiated, it is used here if available, as 541 servers featuring extended security are likely supporting also 542 NTLMv2. */ 543 result = Curl_rand(data, entropy, 8); 544 if(result) 545 return result; 546 547 result = Curl_ntlm_core_mk_nt_hash(passwdp, ntbuffer); 548 if(result) 549 return result; 550 551 result = Curl_ntlm_core_mk_ntlmv2_hash(user, userlen, domain, domlen, 552 ntbuffer, ntlmv2hash); 553 if(result) 554 return result; 555 556 /* LMv2 response */ 557 result = Curl_ntlm_core_mk_lmv2_resp(ntlmv2hash, entropy, 558 &ntlm->nonce[0], lmresp); 559 if(result) 560 return result; 561 562 /* NTLMv2 response */ 563 result = Curl_ntlm_core_mk_ntlmv2_resp(ntlmv2hash, entropy, 564 ntlm, &ntlmv2resp, &ntresplen); 565 if(result) 566 return result; 567 568 ptr_ntresp = ntlmv2resp; 569 } 570 else { 571 572 unsigned char ntbuffer[0x18]; 573 unsigned char lmbuffer[0x18]; 574 575 /* NTLM version 1 */ 576 577 result = Curl_ntlm_core_mk_nt_hash(passwdp, ntbuffer); 578 if(result) 579 return result; 580 581 Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], ntresp); 582 583 result = Curl_ntlm_core_mk_lm_hash(passwdp, lmbuffer); 584 if(result) 585 return result; 586 587 Curl_ntlm_core_lm_resp(lmbuffer, &ntlm->nonce[0], lmresp); 588 ntlm->flags &= ~NTLMFLAG_NEGOTIATE_NTLM2_KEY; 589 590 /* A safer but less compatible alternative is: 591 * Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], lmresp); 592 * See https://davenport.sourceforge.net/ntlm.html#ntlmVersion2 */ 593 } 594 595 if(unicode) { 596 domlen = domlen * 2; 597 userlen = userlen * 2; 598 hostlen = hostlen * 2; 599 } 600 601 lmrespoff = 64; /* size of the message header */ 602 ntrespoff = lmrespoff + 0x18; 603 domoff = ntrespoff + ntresplen; 604 useroff = domoff + domlen; 605 hostoff = useroff + userlen; 606 607 /* Create the big type-3 message binary blob */ 608 size = msnprintf((char *)ntlmbuf, NTLM_BUFSIZE, 609 NTLMSSP_SIGNATURE "%c" 610 "\x03%c%c%c" /* 32-bit type = 3 */ 611 612 "%c%c" /* LanManager length */ 613 "%c%c" /* LanManager allocated space */ 614 "%c%c" /* LanManager offset */ 615 "%c%c" /* 2 zeroes */ 616 617 "%c%c" /* NT-response length */ 618 "%c%c" /* NT-response allocated space */ 619 "%c%c" /* NT-response offset */ 620 "%c%c" /* 2 zeroes */ 621 622 "%c%c" /* domain length */ 623 "%c%c" /* domain allocated space */ 624 "%c%c" /* domain name offset */ 625 "%c%c" /* 2 zeroes */ 626 627 "%c%c" /* user length */ 628 "%c%c" /* user allocated space */ 629 "%c%c" /* user offset */ 630 "%c%c" /* 2 zeroes */ 631 632 "%c%c" /* host length */ 633 "%c%c" /* host allocated space */ 634 "%c%c" /* host offset */ 635 "%c%c" /* 2 zeroes */ 636 637 "%c%c" /* session key length (unknown purpose) */ 638 "%c%c" /* session key allocated space (unknown purpose) */ 639 "%c%c" /* session key offset (unknown purpose) */ 640 "%c%c" /* 2 zeroes */ 641 642 "%c%c%c%c", /* flags */ 643 644 /* domain string */ 645 /* user string */ 646 /* host string */ 647 /* LanManager response */ 648 /* NT response */ 649 650 0, /* null-termination */ 651 0, 0, 0, /* type-3 long, the 24 upper bits */ 652 653 SHORTPAIR(0x18), /* LanManager response length, twice */ 654 SHORTPAIR(0x18), 655 SHORTPAIR(lmrespoff), 656 0x0, 0x0, 657 658 SHORTPAIR(ntresplen), /* NT-response length, twice */ 659 SHORTPAIR(ntresplen), 660 SHORTPAIR(ntrespoff), 661 0x0, 0x0, 662 663 SHORTPAIR(domlen), 664 SHORTPAIR(domlen), 665 SHORTPAIR(domoff), 666 0x0, 0x0, 667 668 SHORTPAIR(userlen), 669 SHORTPAIR(userlen), 670 SHORTPAIR(useroff), 671 0x0, 0x0, 672 673 SHORTPAIR(hostlen), 674 SHORTPAIR(hostlen), 675 SHORTPAIR(hostoff), 676 0x0, 0x0, 677 678 0x0, 0x0, 679 0x0, 0x0, 680 0x0, 0x0, 681 0x0, 0x0, 682 683 LONGQUARTET(ntlm->flags)); 684 685 DEBUGASSERT(size == 64); 686 DEBUGASSERT(size == (size_t)lmrespoff); 687 688 /* We append the binary hashes */ 689 if(size < (NTLM_BUFSIZE - 0x18)) { 690 memcpy(&ntlmbuf[size], lmresp, 0x18); 691 size += 0x18; 692 } 693 694 DEBUG_OUT({ 695 fprintf(stderr, "**** TYPE3 header lmresp="); 696 ntlm_print_hex(stderr, (char *)&ntlmbuf[lmrespoff], 0x18); 697 }); 698 699 /* ntresplen + size should not be risking an integer overflow here */ 700 if(ntresplen + size > sizeof(ntlmbuf)) { 701 failf(data, "incoming NTLM message too big"); 702 return CURLE_OUT_OF_MEMORY; 703 } 704 DEBUGASSERT(size == (size_t)ntrespoff); 705 memcpy(&ntlmbuf[size], ptr_ntresp, ntresplen); 706 size += ntresplen; 707 708 DEBUG_OUT({ 709 fprintf(stderr, "\n ntresp="); 710 ntlm_print_hex(stderr, (char *)&ntlmbuf[ntrespoff], ntresplen); 711 }); 712 713 free(ntlmv2resp);/* Free the dynamic buffer allocated for NTLMv2 */ 714 715 DEBUG_OUT({ 716 fprintf(stderr, "\n flags=0x%02.2x%02.2x%02.2x%02.2x 0x%08.8x ", 717 LONGQUARTET(ntlm->flags), ntlm->flags); 718 ntlm_print_flags(stderr, ntlm->flags); 719 fprintf(stderr, "\n****\n"); 720 }); 721 722 /* Make sure that the domain, user and host strings fit in the 723 buffer before we copy them there. */ 724 if(size + userlen + domlen + hostlen >= NTLM_BUFSIZE) { 725 failf(data, "user + domain + host name too big"); 726 return CURLE_OUT_OF_MEMORY; 727 } 728 729 DEBUGASSERT(size == domoff); 730 if(unicode) 731 unicodecpy(&ntlmbuf[size], domain, domlen / 2); 732 else 733 memcpy(&ntlmbuf[size], domain, domlen); 734 735 size += domlen; 736 737 DEBUGASSERT(size == useroff); 738 if(unicode) 739 unicodecpy(&ntlmbuf[size], user, userlen / 2); 740 else 741 memcpy(&ntlmbuf[size], user, userlen); 742 743 size += userlen; 744 745 DEBUGASSERT(size == hostoff); 746 if(unicode) 747 unicodecpy(&ntlmbuf[size], host, hostlen / 2); 748 else 749 memcpy(&ntlmbuf[size], host, hostlen); 750 751 size += hostlen; 752 753 /* Return the binary blob. */ 754 result = Curl_bufref_memdup(out, ntlmbuf, size); 755 756 Curl_auth_cleanup_ntlm(ntlm); 757 758 return result; 759} 760 761/* 762 * Curl_auth_cleanup_ntlm() 763 * 764 * This is used to clean up the NTLM specific data. 765 * 766 * Parameters: 767 * 768 * ntlm [in/out] - The NTLM data struct being cleaned up. 769 * 770 */ 771void Curl_auth_cleanup_ntlm(struct ntlmdata *ntlm) 772{ 773 /* Free the target info */ 774 Curl_safefree(ntlm->target_info); 775 776 /* Reset any variables */ 777 ntlm->target_info_len = 0; 778} 779 780#endif /* USE_NTLM && !USE_WINDOWS_SSPI */ 781