1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "net/http/http_auth_handler_ntlm.h" 6 7 #include <stdlib.h> 8 // For gethostname 9 #if defined(OS_POSIX) 10 #include <unistd.h> 11 #elif defined(OS_WIN) 12 #include <winsock2.h> 13 #endif 14 15 #include "base/md5.h" 16 #include "base/rand_util.h" 17 #include "base/string_util.h" 18 #include "base/sys_string_conversions.h" 19 #include "base/utf_string_conversions.h" 20 #include "net/base/net_errors.h" 21 #include "net/base/net_util.h" 22 #include "net/http/des.h" 23 #include "net/http/md4.h" 24 25 namespace net { 26 27 // Based on mozilla/security/manager/ssl/src/nsNTLMAuthModule.cpp, 28 // CVS rev. 1.14. 29 // 30 // TODO(wtc): 31 // - The IS_BIG_ENDIAN code is not tested. 32 // - Enable the logging code or just delete it. 33 // - Delete or comment out the LM code, which hasn't been tested and isn't 34 // being used. 35 36 /* ***** BEGIN LICENSE BLOCK ***** 37 * Version: MPL 1.1/GPL 2.0/LGPL 2.1 38 * 39 * The contents of this file are subject to the Mozilla Public License Version 40 * 1.1 (the "License"); you may not use this file except in compliance with 41 * the License. You may obtain a copy of the License at 42 * http://www.mozilla.org/MPL/ 43 * 44 * Software distributed under the License is distributed on an "AS IS" basis, 45 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 46 * for the specific language governing rights and limitations under the 47 * License. 48 * 49 * The Original Code is Mozilla. 50 * 51 * The Initial Developer of the Original Code is IBM Corporation. 52 * Portions created by IBM Corporation are Copyright (C) 2003 53 * IBM Corporation. All Rights Reserved. 54 * 55 * Contributor(s): 56 * Darin Fisher <darin (at) meer.net> 57 * 58 * Alternatively, the contents of this file may be used under the terms of 59 * either the GNU General Public License Version 2 or later (the "GPL"), or 60 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), 61 * in which case the provisions of the GPL or the LGPL are applicable instead 62 * of those above. If you wish to allow use of your version of this file only 63 * under the terms of either the GPL or the LGPL, and not to allow others to 64 * use your version of this file under the terms of the MPL, indicate your 65 * decision by deleting the provisions above and replace them with the notice 66 * and other provisions required by the GPL or the LGPL. If you do not delete 67 * the provisions above, a recipient may use your version of this file under 68 * the terms of any one of the MPL, the GPL or the LGPL. 69 * 70 * ***** END LICENSE BLOCK ***** */ 71 72 // Discover the endianness by testing processor architecture. 73 #if defined(ARCH_CPU_X86) || defined(ARCH_CPU_X86_64) || defined(ARCH_CPU_ARMEL) 74 #define IS_LITTLE_ENDIAN 1 75 #undef IS_BIG_ENDIAN 76 #else 77 #error "Unknown endianness" 78 #endif 79 80 #define NTLM_LOG(x) ((void) 0) 81 82 //----------------------------------------------------------------------------- 83 // This file contains a cross-platform NTLM authentication implementation. It 84 // is based on documentation from: http://davenport.sourceforge.net/ntlm.html 85 //----------------------------------------------------------------------------- 86 87 enum { 88 NTLM_NegotiateUnicode = 0x00000001, 89 NTLM_NegotiateOEM = 0x00000002, 90 NTLM_RequestTarget = 0x00000004, 91 NTLM_Unknown1 = 0x00000008, 92 NTLM_NegotiateSign = 0x00000010, 93 NTLM_NegotiateSeal = 0x00000020, 94 NTLM_NegotiateDatagramStyle = 0x00000040, 95 NTLM_NegotiateLanManagerKey = 0x00000080, 96 NTLM_NegotiateNetware = 0x00000100, 97 NTLM_NegotiateNTLMKey = 0x00000200, 98 NTLM_Unknown2 = 0x00000400, 99 NTLM_Unknown3 = 0x00000800, 100 NTLM_NegotiateDomainSupplied = 0x00001000, 101 NTLM_NegotiateWorkstationSupplied = 0x00002000, 102 NTLM_NegotiateLocalCall = 0x00004000, 103 NTLM_NegotiateAlwaysSign = 0x00008000, 104 NTLM_TargetTypeDomain = 0x00010000, 105 NTLM_TargetTypeServer = 0x00020000, 106 NTLM_TargetTypeShare = 0x00040000, 107 NTLM_NegotiateNTLM2Key = 0x00080000, 108 NTLM_RequestInitResponse = 0x00100000, 109 NTLM_RequestAcceptResponse = 0x00200000, 110 NTLM_RequestNonNTSessionKey = 0x00400000, 111 NTLM_NegotiateTargetInfo = 0x00800000, 112 NTLM_Unknown4 = 0x01000000, 113 NTLM_Unknown5 = 0x02000000, 114 NTLM_Unknown6 = 0x04000000, 115 NTLM_Unknown7 = 0x08000000, 116 NTLM_Unknown8 = 0x10000000, 117 NTLM_Negotiate128 = 0x20000000, 118 NTLM_NegotiateKeyExchange = 0x40000000, 119 NTLM_Negotiate56 = 0x80000000 120 }; 121 122 // We send these flags with our type 1 message. 123 enum { 124 NTLM_TYPE1_FLAGS = (NTLM_NegotiateUnicode | 125 NTLM_NegotiateOEM | 126 NTLM_RequestTarget | 127 NTLM_NegotiateNTLMKey | 128 NTLM_NegotiateAlwaysSign | 129 NTLM_NegotiateNTLM2Key) 130 }; 131 132 static const char NTLM_SIGNATURE[] = "NTLMSSP"; 133 static const char NTLM_TYPE1_MARKER[] = { 0x01, 0x00, 0x00, 0x00 }; 134 static const char NTLM_TYPE2_MARKER[] = { 0x02, 0x00, 0x00, 0x00 }; 135 static const char NTLM_TYPE3_MARKER[] = { 0x03, 0x00, 0x00, 0x00 }; 136 137 enum { 138 NTLM_TYPE1_HEADER_LEN = 32, 139 NTLM_TYPE2_HEADER_LEN = 32, 140 NTLM_TYPE3_HEADER_LEN = 64, 141 142 LM_HASH_LEN = 16, 143 LM_RESP_LEN = 24, 144 145 NTLM_HASH_LEN = 16, 146 NTLM_RESP_LEN = 24 147 }; 148 149 //----------------------------------------------------------------------------- 150 151 // The return value of this function controls whether or not the LM hash will 152 // be included in response to a NTLM challenge. 153 // 154 // In Mozilla, this function returns the value of the boolean preference 155 // "network.ntlm.send-lm-response". By default, the preference is disabled 156 // since servers should almost never need the LM hash, and the LM hash is what 157 // makes NTLM authentication less secure. See 158 // https://bugzilla.mozilla.org/show_bug.cgi?id=250691 for further details. 159 // 160 // We just return a hardcoded false. 161 static bool SendLM() { 162 return false; 163 } 164 165 //----------------------------------------------------------------------------- 166 167 #define LogFlags(x) ((void) 0) 168 #define LogBuf(a, b, c) ((void) 0) 169 #define LogToken(a, b, c) ((void) 0) 170 171 //----------------------------------------------------------------------------- 172 173 // Byte order swapping. 174 #define SWAP16(x) ((((x) & 0xff) << 8) | (((x) >> 8) & 0xff)) 175 #define SWAP32(x) ((SWAP16((x) & 0xffff) << 16) | (SWAP16((x) >> 16))) 176 177 static void* WriteBytes(void* buf, const void* data, uint32 data_len) { 178 memcpy(buf, data, data_len); 179 return static_cast<char*>(buf) + data_len; 180 } 181 182 static void* WriteDWORD(void* buf, uint32 dword) { 183 #ifdef IS_BIG_ENDIAN 184 // NTLM uses little endian on the wire. 185 dword = SWAP32(dword); 186 #endif 187 return WriteBytes(buf, &dword, sizeof(dword)); 188 } 189 190 static void* WriteSecBuf(void* buf, uint16 length, uint32 offset) { 191 #ifdef IS_BIG_ENDIAN 192 length = SWAP16(length); 193 offset = SWAP32(offset); 194 #endif 195 buf = WriteBytes(buf, &length, sizeof(length)); 196 buf = WriteBytes(buf, &length, sizeof(length)); 197 buf = WriteBytes(buf, &offset, sizeof(offset)); 198 return buf; 199 } 200 201 #ifdef IS_BIG_ENDIAN 202 /** 203 * WriteUnicodeLE copies a unicode string from one buffer to another. The 204 * resulting unicode string is in little-endian format. The input string is 205 * assumed to be in the native endianness of the local machine. It is safe 206 * to pass the same buffer as both input and output, which is a handy way to 207 * convert the unicode buffer to little-endian on big-endian platforms. 208 */ 209 static void* WriteUnicodeLE(void* buf, const char16* str, uint32 str_len) { 210 // Convert input string from BE to LE. 211 uint8* cursor = static_cast<uint8*>(buf); 212 const uint8* input = reinterpret_cast<const uint8*>(str); 213 for (uint32 i = 0; i < str_len; ++i, input += 2, cursor += 2) { 214 // Allow for the case where |buf == str|. 215 uint8 temp = input[0]; 216 cursor[0] = input[1]; 217 cursor[1] = temp; 218 } 219 return buf; 220 } 221 #endif 222 223 static uint16 ReadUint16(const uint8*& buf) { 224 uint16 x = (static_cast<uint16>(buf[0])) | 225 (static_cast<uint16>(buf[1]) << 8); 226 buf += sizeof(x); 227 return x; 228 } 229 230 static uint32 ReadUint32(const uint8*& buf) { 231 uint32 x = (static_cast<uint32>(buf[0])) | 232 (static_cast<uint32>(buf[1]) << 8) | 233 (static_cast<uint32>(buf[2]) << 16) | 234 (static_cast<uint32>(buf[3]) << 24); 235 buf += sizeof(x); 236 return x; 237 } 238 239 //----------------------------------------------------------------------------- 240 241 static void ZapBuf(void* buf, size_t buf_len) { 242 memset(buf, 0, buf_len); 243 } 244 245 // TODO(wtc): Can we implement ZapString as 246 // s.replace(0, s.size(), s.size(), '\0)? 247 static void ZapString(std::string* s) { 248 ZapBuf(&(*s)[0], s->length()); 249 } 250 251 static void ZapString(string16* s) { 252 ZapBuf(&(*s)[0], s->length() * 2); 253 } 254 255 // LM_Hash computes the LM hash of the given password. 256 // 257 // param password 258 // unicode password. 259 // param hash 260 // 16-byte result buffer 261 // 262 // Note: This function is not being used because our SendLM() function always 263 // returns false. 264 static void LM_Hash(const string16& password, uint8* hash) { 265 static const uint8 LM_MAGIC[] = "KGS!@#$%"; 266 267 // Convert password to OEM character set. We'll just use the native 268 // filesystem charset. 269 std::string passbuf = base::SysWideToNativeMB(UTF16ToWide(password)); 270 StringToUpperASCII(&passbuf); 271 passbuf.resize(14, '\0'); 272 273 uint8 k1[8], k2[8]; 274 DESMakeKey(reinterpret_cast<const uint8*>(passbuf.data()) , k1); 275 DESMakeKey(reinterpret_cast<const uint8*>(passbuf.data()) + 7, k2); 276 ZapString(&passbuf); 277 278 // Use password keys to hash LM magic string twice. 279 DESEncrypt(k1, LM_MAGIC, hash); 280 DESEncrypt(k2, LM_MAGIC, hash + 8); 281 } 282 283 // NTLM_Hash computes the NTLM hash of the given password. 284 // 285 // param password 286 // null-terminated unicode password. 287 // param hash 288 // 16-byte result buffer 289 static void NTLM_Hash(const string16& password, uint8* hash) { 290 #ifdef IS_BIG_ENDIAN 291 uint32 len = password.length(); 292 uint8* passbuf; 293 294 passbuf = static_cast<uint8*>(malloc(len * 2)); 295 WriteUnicodeLE(passbuf, password.data(), len); 296 weak_crypto::MD4Sum(passbuf, len * 2, hash); 297 298 ZapBuf(passbuf, len * 2); 299 free(passbuf); 300 #else 301 weak_crypto::MD4Sum(reinterpret_cast<const uint8*>(password.data()), 302 password.length() * 2, hash); 303 #endif 304 } 305 306 //----------------------------------------------------------------------------- 307 308 // LM_Response generates the LM response given a 16-byte password hash and the 309 // challenge from the Type-2 message. 310 // 311 // param hash 312 // 16-byte password hash 313 // param challenge 314 // 8-byte challenge from Type-2 message 315 // param response 316 // 24-byte buffer to contain the LM response upon return 317 static void LM_Response(const uint8* hash, 318 const uint8* challenge, 319 uint8* response) { 320 uint8 keybytes[21], k1[8], k2[8], k3[8]; 321 322 memcpy(keybytes, hash, 16); 323 ZapBuf(keybytes + 16, 5); 324 325 DESMakeKey(keybytes , k1); 326 DESMakeKey(keybytes + 7, k2); 327 DESMakeKey(keybytes + 14, k3); 328 329 DESEncrypt(k1, challenge, response); 330 DESEncrypt(k2, challenge, response + 8); 331 DESEncrypt(k3, challenge, response + 16); 332 } 333 334 //----------------------------------------------------------------------------- 335 336 // Returns OK or a network error code. 337 static int GenerateType1Msg(void** out_buf, uint32* out_len) { 338 // 339 // Verify that buf_len is sufficient. 340 // 341 *out_len = NTLM_TYPE1_HEADER_LEN; 342 *out_buf = malloc(*out_len); 343 if (!*out_buf) 344 return ERR_OUT_OF_MEMORY; 345 346 // 347 // Write out type 1 message. 348 // 349 void* cursor = *out_buf; 350 351 // 0 : signature 352 cursor = WriteBytes(cursor, NTLM_SIGNATURE, sizeof(NTLM_SIGNATURE)); 353 354 // 8 : marker 355 cursor = WriteBytes(cursor, NTLM_TYPE1_MARKER, sizeof(NTLM_TYPE1_MARKER)); 356 357 // 12 : flags 358 cursor = WriteDWORD(cursor, NTLM_TYPE1_FLAGS); 359 360 // 361 // NOTE: It is common for the domain and workstation fields to be empty. 362 // This is true of Win2k clients, and my guess is that there is 363 // little utility to sending these strings before the charset has 364 // been negotiated. We follow suite -- anyways, it doesn't hurt 365 // to save some bytes on the wire ;-) 366 // 367 368 // 16 : supplied domain security buffer (empty) 369 cursor = WriteSecBuf(cursor, 0, 0); 370 371 // 24 : supplied workstation security buffer (empty) 372 cursor = WriteSecBuf(cursor, 0, 0); 373 374 return OK; 375 } 376 377 struct Type2Msg { 378 uint32 flags; // NTLM_Xxx bitwise combination 379 uint8 challenge[8]; // 8 byte challenge 380 const void* target; // target string (type depends on flags) 381 uint32 target_len; // target length in bytes 382 }; 383 384 // Returns OK or a network error code. 385 // TODO(wtc): This function returns ERR_UNEXPECTED when the input message is 386 // invalid. We should return a better error code. 387 static int ParseType2Msg(const void* in_buf, uint32 in_len, Type2Msg* msg) { 388 // Make sure in_buf is long enough to contain a meaningful type2 msg. 389 // 390 // 0 NTLMSSP Signature 391 // 8 NTLM Message Type 392 // 12 Target Name 393 // 20 Flags 394 // 24 Challenge 395 // 32 end of header, start of optional data blocks 396 // 397 if (in_len < NTLM_TYPE2_HEADER_LEN) 398 return ERR_UNEXPECTED; 399 400 const uint8* cursor = (const uint8*) in_buf; 401 402 // verify NTLMSSP signature 403 if (memcmp(cursor, NTLM_SIGNATURE, sizeof(NTLM_SIGNATURE)) != 0) 404 return ERR_UNEXPECTED; 405 cursor += sizeof(NTLM_SIGNATURE); 406 407 // verify Type-2 marker 408 if (memcmp(cursor, NTLM_TYPE2_MARKER, sizeof(NTLM_TYPE2_MARKER)) != 0) 409 return ERR_UNEXPECTED; 410 cursor += sizeof(NTLM_TYPE2_MARKER); 411 412 // read target name security buffer 413 uint32 target_len = ReadUint16(cursor); 414 ReadUint16(cursor); // discard next 16-bit value 415 uint32 offset = ReadUint32(cursor); // get offset from in_buf 416 msg->target_len = 0; 417 msg->target = NULL; 418 // Check the offset / length combo is in range of the input buffer, including 419 // integer overflow checking. 420 if (offset + target_len > offset && offset + target_len <= in_len) { 421 msg->target_len = target_len; 422 msg->target = ((const uint8*) in_buf) + offset; 423 } 424 425 // read flags 426 msg->flags = ReadUint32(cursor); 427 428 // read challenge 429 memcpy(msg->challenge, cursor, sizeof(msg->challenge)); 430 cursor += sizeof(msg->challenge); 431 432 NTLM_LOG(("NTLM type 2 message:\n")); 433 LogBuf("target", (const uint8*) msg->target, msg->target_len); 434 LogBuf("flags", (const uint8*) &msg->flags, 4); 435 LogFlags(msg->flags); 436 LogBuf("challenge", msg->challenge, sizeof(msg->challenge)); 437 438 // We currently do not implement LMv2/NTLMv2 or NTLM2 responses, 439 // so we can ignore target information. We may want to enable 440 // support for these alternate mechanisms in the future. 441 return OK; 442 } 443 444 static void GenerateRandom(uint8* output, size_t n) { 445 for (size_t i = 0; i < n; ++i) 446 output[i] = base::RandInt(0, 255); 447 } 448 449 // Returns OK or a network error code. 450 static int GenerateType3Msg(const string16& domain, 451 const string16& username, 452 const string16& password, 453 const std::string& hostname, 454 const void* rand_8_bytes, 455 const void* in_buf, 456 uint32 in_len, 457 void** out_buf, 458 uint32* out_len) { 459 // in_buf contains Type-2 msg (the challenge) from server. 460 461 int rv; 462 Type2Msg msg; 463 464 rv = ParseType2Msg(in_buf, in_len, &msg); 465 if (rv != OK) 466 return rv; 467 468 bool unicode = (msg.flags & NTLM_NegotiateUnicode) != 0; 469 470 // Temporary buffers for unicode strings 471 #ifdef IS_BIG_ENDIAN 472 string16 ucs_domain_buf, ucs_user_buf; 473 #endif 474 string16 ucs_host_buf; 475 // Temporary buffers for oem strings 476 std::string oem_domain_buf, oem_user_buf; 477 // Pointers and lengths for the string buffers; encoding is unicode if 478 // the "negotiate unicode" flag was set in the Type-2 message. 479 const void* domain_ptr; 480 const void* user_ptr; 481 const void* host_ptr; 482 uint32 domain_len, user_len, host_len; 483 484 // 485 // Get domain name. 486 // 487 if (unicode) { 488 #ifdef IS_BIG_ENDIAN 489 ucs_domain_buf = domain; 490 domain_ptr = ucs_domain_buf.data(); 491 domain_len = ucs_domain_buf.length() * 2; 492 WriteUnicodeLE(const_cast<void*>(domain_ptr), (const char16*) domain_ptr, 493 ucs_domain_buf.length()); 494 #else 495 domain_ptr = domain.data(); 496 domain_len = domain.length() * 2; 497 #endif 498 } else { 499 oem_domain_buf = base::SysWideToNativeMB(UTF16ToWide(domain)); 500 domain_ptr = oem_domain_buf.data(); 501 domain_len = oem_domain_buf.length(); 502 } 503 504 // 505 // Get user name. 506 // 507 if (unicode) { 508 #ifdef IS_BIG_ENDIAN 509 ucs_user_buf = username; 510 user_ptr = ucs_user_buf.data(); 511 user_len = ucs_user_buf.length() * 2; 512 WriteUnicodeLE(const_cast<void*>(user_ptr), (const char16*) user_ptr, 513 ucs_user_buf.length()); 514 #else 515 user_ptr = username.data(); 516 user_len = username.length() * 2; 517 #endif 518 } else { 519 oem_user_buf = base::SysWideToNativeMB(UTF16ToWide(username)); 520 user_ptr = oem_user_buf.data(); 521 user_len = oem_user_buf.length(); 522 } 523 524 // 525 // Get workstation name (use local machine's hostname). 526 // 527 if (unicode) { 528 // hostname is ASCII, so we can do a simple zero-pad expansion: 529 ucs_host_buf.assign(hostname.begin(), hostname.end()); 530 host_ptr = ucs_host_buf.data(); 531 host_len = ucs_host_buf.length() * 2; 532 #ifdef IS_BIG_ENDIAN 533 WriteUnicodeLE(const_cast<void*>(host_ptr), (const char16*) host_ptr, 534 ucs_host_buf.length()); 535 #endif 536 } else { 537 host_ptr = hostname.data(); 538 host_len = hostname.length(); 539 } 540 541 // 542 // Now that we have generated all of the strings, we can allocate out_buf. 543 // 544 *out_len = NTLM_TYPE3_HEADER_LEN + host_len + domain_len + user_len + 545 LM_RESP_LEN + NTLM_RESP_LEN; 546 *out_buf = malloc(*out_len); 547 if (!*out_buf) 548 return ERR_OUT_OF_MEMORY; 549 550 // 551 // Next, we compute the LM and NTLM responses. 552 // 553 uint8 lm_resp[LM_RESP_LEN]; 554 uint8 ntlm_resp[NTLM_RESP_LEN]; 555 uint8 ntlm_hash[NTLM_HASH_LEN]; 556 if (msg.flags & NTLM_NegotiateNTLM2Key) { 557 // compute NTLM2 session response 558 MD5Digest session_hash; 559 uint8 temp[16]; 560 561 memcpy(lm_resp, rand_8_bytes, 8); 562 memset(lm_resp + 8, 0, LM_RESP_LEN - 8); 563 564 memcpy(temp, msg.challenge, 8); 565 memcpy(temp + 8, lm_resp, 8); 566 MD5Sum(temp, 16, &session_hash); 567 568 NTLM_Hash(password, ntlm_hash); 569 LM_Response(ntlm_hash, session_hash.a, ntlm_resp); 570 } else { 571 NTLM_Hash(password, ntlm_hash); 572 LM_Response(ntlm_hash, msg.challenge, ntlm_resp); 573 574 if (SendLM()) { 575 uint8 lm_hash[LM_HASH_LEN]; 576 LM_Hash(password, lm_hash); 577 LM_Response(lm_hash, msg.challenge, lm_resp); 578 } else { 579 // According to http://davenport.sourceforge.net/ntlm.html#ntlmVersion2, 580 // the correct way to not send the LM hash is to send the NTLM hash twice 581 // in both the LM and NTLM response fields. 582 LM_Response(ntlm_hash, msg.challenge, lm_resp); 583 } 584 } 585 586 // 587 // Finally, we assemble the Type-3 msg :-) 588 // 589 void* cursor = *out_buf; 590 uint32 offset; 591 592 // 0 : signature 593 cursor = WriteBytes(cursor, NTLM_SIGNATURE, sizeof(NTLM_SIGNATURE)); 594 595 // 8 : marker 596 cursor = WriteBytes(cursor, NTLM_TYPE3_MARKER, sizeof(NTLM_TYPE3_MARKER)); 597 598 // 12 : LM response sec buf 599 offset = NTLM_TYPE3_HEADER_LEN + domain_len + user_len + host_len; 600 cursor = WriteSecBuf(cursor, LM_RESP_LEN, offset); 601 memcpy(static_cast<uint8*>(*out_buf) + offset, lm_resp, LM_RESP_LEN); 602 603 // 20 : NTLM response sec buf 604 offset += LM_RESP_LEN; 605 cursor = WriteSecBuf(cursor, NTLM_RESP_LEN, offset); 606 memcpy(static_cast<uint8*>(*out_buf) + offset, ntlm_resp, NTLM_RESP_LEN); 607 608 // 28 : domain name sec buf 609 offset = NTLM_TYPE3_HEADER_LEN; 610 cursor = WriteSecBuf(cursor, domain_len, offset); 611 memcpy(static_cast<uint8*>(*out_buf) + offset, domain_ptr, domain_len); 612 613 // 36 : user name sec buf 614 offset += domain_len; 615 cursor = WriteSecBuf(cursor, user_len, offset); 616 memcpy(static_cast<uint8*>(*out_buf) + offset, user_ptr, user_len); 617 618 // 44 : workstation (host) name sec buf 619 offset += user_len; 620 cursor = WriteSecBuf(cursor, host_len, offset); 621 memcpy(static_cast<uint8*>(*out_buf) + offset, host_ptr, host_len); 622 623 // 52 : session key sec buf (not used) 624 cursor = WriteSecBuf(cursor, 0, 0); 625 626 // 60 : negotiated flags 627 cursor = WriteDWORD(cursor, msg.flags & NTLM_TYPE1_FLAGS); 628 629 return OK; 630 } 631 632 // NTLM authentication is specified in "NTLM Over HTTP Protocol Specification" 633 // [MS-NTHT]. 634 635 // static 636 HttpAuthHandlerNTLM::GenerateRandomProc 637 HttpAuthHandlerNTLM::generate_random_proc_ = GenerateRandom; 638 639 // static 640 HttpAuthHandlerNTLM::HostNameProc 641 HttpAuthHandlerNTLM::get_host_name_proc_ = GetHostName; 642 643 HttpAuthHandlerNTLM::HttpAuthHandlerNTLM() { 644 } 645 646 bool HttpAuthHandlerNTLM::NeedsIdentity() { 647 // This gets called for each round-trip. Only require identity on 648 // the first call (when auth_data_ is empty). On subsequent calls, 649 // we use the initially established identity. 650 return auth_data_.empty(); 651 } 652 653 bool HttpAuthHandlerNTLM::AllowsDefaultCredentials() { 654 // Default credentials are not supported in the portable implementation of 655 // NTLM, but are supported in the SSPI implementation. 656 return false; 657 } 658 659 int HttpAuthHandlerNTLM::InitializeBeforeFirstChallenge() { 660 return OK; 661 } 662 663 HttpAuthHandlerNTLM::~HttpAuthHandlerNTLM() { 664 // Wipe our copy of the password from memory, to reduce the chance of being 665 // written to the paging file on disk. 666 ZapString(&password_); 667 } 668 669 // static 670 HttpAuthHandlerNTLM::GenerateRandomProc 671 HttpAuthHandlerNTLM::SetGenerateRandomProc( 672 GenerateRandomProc proc) { 673 GenerateRandomProc old_proc = generate_random_proc_; 674 generate_random_proc_ = proc; 675 return old_proc; 676 } 677 678 // static 679 HttpAuthHandlerNTLM::HostNameProc HttpAuthHandlerNTLM::SetHostNameProc( 680 HostNameProc proc) { 681 HostNameProc old_proc = get_host_name_proc_; 682 get_host_name_proc_ = proc; 683 return old_proc; 684 } 685 686 HttpAuthHandlerNTLM::Factory::Factory() { 687 } 688 689 HttpAuthHandlerNTLM::Factory::~Factory() { 690 } 691 692 int HttpAuthHandlerNTLM::GetNextToken(const void* in_token, 693 uint32 in_token_len, 694 void** out_token, 695 uint32* out_token_len) { 696 int rv = 0; 697 698 // If in_token is non-null, then assume it contains a type 2 message... 699 if (in_token) { 700 LogToken("in-token", in_token, in_token_len); 701 std::string hostname = get_host_name_proc_(); 702 if (hostname.empty()) 703 return ERR_UNEXPECTED; 704 uint8 rand_buf[8]; 705 generate_random_proc_(rand_buf, 8); 706 rv = GenerateType3Msg(domain_, username_, password_, hostname, rand_buf, 707 in_token, in_token_len, out_token, out_token_len); 708 } else { 709 rv = GenerateType1Msg(out_token, out_token_len); 710 } 711 712 if (rv == OK) 713 LogToken("out-token", *out_token, *out_token_len); 714 715 return rv; 716 } 717 718 int HttpAuthHandlerNTLM::Factory::CreateAuthHandler( 719 HttpAuth::ChallengeTokenizer* challenge, 720 HttpAuth::Target target, 721 const GURL& origin, 722 CreateReason reason, 723 int digest_nonce_count, 724 const BoundNetLog& net_log, 725 scoped_ptr<HttpAuthHandler>* handler) { 726 if (reason == CREATE_PREEMPTIVE) 727 return ERR_UNSUPPORTED_AUTH_SCHEME; 728 // TODO(cbentzel): Move towards model of parsing in the factory 729 // method and only constructing when valid. 730 // NOTE: Default credentials are not supported for the portable implementation 731 // of NTLM. 732 scoped_ptr<HttpAuthHandler> tmp_handler(new HttpAuthHandlerNTLM); 733 if (!tmp_handler->InitFromChallenge(challenge, target, origin, net_log)) 734 return ERR_INVALID_RESPONSE; 735 handler->swap(tmp_handler); 736 return OK; 737 } 738 739 } // namespace net 740