Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(140)

Side by Side Diff: net/http/http_auth_handler_ntlm.cc

Issue 43113: Merge NTLMAuthModule into HttpAuthHandlerNTLM. The... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Upload before checkin Created 11 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « net/http/http_auth_handler_ntlm.h ('k') | net/http/http_network_transaction_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "net/http/http_auth_handler_ntlm.h" 5 #include "net/http/http_auth_handler_ntlm.h"
6 6
7 #include <stdlib.h> 7 #include <stdlib.h>
8 // For gethostname 8 // For gethostname
9 #if defined(OS_POSIX) 9 #if defined(OS_POSIX)
10 #include <unistd.h> 10 #include <unistd.h>
11 #elif defined(OS_WIN) 11 #elif defined(OS_WIN)
12 #include <winsock2.h> 12 #include <winsock2.h>
13 #endif 13 #endif
14 14
15 #include "base/md5.h" 15 #include "base/md5.h"
16 #include "base/rand_util.h" 16 #include "base/rand_util.h"
17 #include "base/string_util.h" 17 #include "base/string_util.h"
18 #include "base/sys_string_conversions.h" 18 #include "base/sys_string_conversions.h"
19 #include "net/base/base64.h" 19 #include "net/base/base64.h"
20 #include "net/base/net_errors.h" 20 #include "net/base/net_errors.h"
21 #include "net/base/net_util.h"
21 #include "net/http/des.h" 22 #include "net/http/des.h"
22 #include "net/http/md4.h" 23 #include "net/http/md4.h"
23 24
24 namespace net { 25 namespace net {
25 26
26 // Based on mozilla/security/manager/ssl/src/nsNTLMAuthModule.cpp, 27 // Based on mozilla/security/manager/ssl/src/nsNTLMAuthModule.cpp,
27 // CVS rev. 1.14. 28 // CVS rev. 1.14.
28 // 29 //
29 // TODO(wtc): 30 // TODO(wtc):
30 // - The IS_BIG_ENDIAN code is not tested. 31 // - The IS_BIG_ENDIAN code is not tested.
(...skipping 401 matching lines...) Expand 10 before | Expand all | Expand 10 after
432 // so we can ignore target information. We may want to enable 433 // so we can ignore target information. We may want to enable
433 // support for these alternate mechanisms in the future. 434 // support for these alternate mechanisms in the future.
434 return OK; 435 return OK;
435 } 436 }
436 437
437 static void GenerateRandom(uint8* output, size_t n) { 438 static void GenerateRandom(uint8* output, size_t n) {
438 for (size_t i = 0; i < n; ++i) 439 for (size_t i = 0; i < n; ++i)
439 output[i] = base::RandInt(0, 255); 440 output[i] = base::RandInt(0, 255);
440 } 441 }
441 442
442 static void GetHostName(char* name, size_t namelen) {
443 if (gethostname(name, namelen) != 0)
444 name[0] = '\0';
445 }
446
447 // TODO(wtc): these two function pointers should become static members of
448 // HttpAuthHandlerNTLM. They are file-scope static variables now so that
449 // GenerateType3Msg can use them without being a friend function. We should
450 // have HttpAuthHandlerNTLM absorb NTLMAuthModule and pass the host name and
451 // random bytes as input arguments to GenerateType3Msg.
452 static HttpAuthHandlerNTLM::GenerateRandomProc generate_random_proc_ =
453 GenerateRandom;
454 static HttpAuthHandlerNTLM::HostNameProc get_host_name_proc_ = GetHostName;
455
456 // Returns OK or a network error code. 443 // Returns OK or a network error code.
457 static int GenerateType3Msg(const string16& domain, 444 static int GenerateType3Msg(const string16& domain,
458 const string16& username, 445 const string16& username,
459 const string16& password, 446 const string16& password,
460 const void* in_buf, 447 const std::string& hostname,
461 uint32 in_len, 448 const void* rand_8_bytes,
462 void** out_buf, 449 const void* in_buf,
463 uint32* out_len) { 450 uint32 in_len,
451 void** out_buf,
452 uint32* out_len) {
464 // in_buf contains Type-2 msg (the challenge) from server. 453 // in_buf contains Type-2 msg (the challenge) from server.
465 454
466 int rv; 455 int rv;
467 Type2Msg msg; 456 Type2Msg msg;
468 457
469 rv = ParseType2Msg(in_buf, in_len, &msg); 458 rv = ParseType2Msg(in_buf, in_len, &msg);
470 if (rv != OK) 459 if (rv != OK)
471 return rv; 460 return rv;
472 461
473 bool unicode = (msg.flags & NTLM_NegotiateUnicode) != 0; 462 bool unicode = (msg.flags & NTLM_NegotiateUnicode) != 0;
474 463
475 // Temporary buffers for unicode strings 464 // Temporary buffers for unicode strings
476 #ifdef IS_BIG_ENDIAN 465 #ifdef IS_BIG_ENDIAN
477 string16 ucs_domain_buf, ucs_user_buf; 466 string16 ucs_domain_buf, ucs_user_buf;
478 #endif 467 #endif
479 string16 ucs_host_buf; 468 string16 ucs_host_buf;
480 // Temporary buffers for oem strings 469 // Temporary buffers for oem strings
481 std::string oem_domain_buf, oem_user_buf, oem_host_buf; 470 std::string oem_domain_buf, oem_user_buf;
482 // Pointers and lengths for the string buffers; encoding is unicode if 471 // Pointers and lengths for the string buffers; encoding is unicode if
483 // the "negotiate unicode" flag was set in the Type-2 message. 472 // the "negotiate unicode" flag was set in the Type-2 message.
484 const void* domain_ptr; 473 const void* domain_ptr;
485 const void* user_ptr; 474 const void* user_ptr;
486 const void* host_ptr; 475 const void* host_ptr;
487 uint32 domain_len, user_len, host_len; 476 uint32 domain_len, user_len, host_len;
488 477
489 // 478 //
490 // Get domain name. 479 // Get domain name.
491 // 480 //
(...skipping 30 matching lines...) Expand all
522 #endif 511 #endif
523 } else { 512 } else {
524 oem_user_buf = base::SysWideToNativeMB(UTF16ToWide(username)); 513 oem_user_buf = base::SysWideToNativeMB(UTF16ToWide(username));
525 user_ptr = oem_user_buf.data(); 514 user_ptr = oem_user_buf.data();
526 user_len = oem_user_buf.length(); 515 user_len = oem_user_buf.length();
527 } 516 }
528 517
529 // 518 //
530 // Get workstation name (use local machine's hostname). 519 // Get workstation name (use local machine's hostname).
531 // 520 //
532 char host_buf[256]; // Host names are limited to 255 bytes.
533 get_host_name_proc_(host_buf, sizeof(host_buf));
534 host_len = strlen(host_buf);
535 if (host_len == 0)
536 return ERR_UNEXPECTED;
537 if (unicode) { 521 if (unicode) {
538 // hostname is ASCII, so we can do a simple zero-pad expansion: 522 // hostname is ASCII, so we can do a simple zero-pad expansion:
539 ucs_host_buf.assign(host_buf, host_buf + host_len); 523 ucs_host_buf.assign(hostname.begin(), hostname.end());
540 host_ptr = ucs_host_buf.data(); 524 host_ptr = ucs_host_buf.data();
541 host_len = ucs_host_buf.length() * 2; 525 host_len = ucs_host_buf.length() * 2;
542 #ifdef IS_BIG_ENDIAN 526 #ifdef IS_BIG_ENDIAN
543 WriteUnicodeLE(const_cast<void*>(host_ptr), (const char16*) host_ptr, 527 WriteUnicodeLE(const_cast<void*>(host_ptr), (const char16*) host_ptr,
544 ucs_host_buf.length()); 528 ucs_host_buf.length());
545 #endif 529 #endif
546 } else { 530 } else {
547 host_ptr = host_buf; 531 host_ptr = hostname.data();
532 host_len = hostname.length();
548 } 533 }
549 534
550 // 535 //
551 // Now that we have generated all of the strings, we can allocate out_buf. 536 // Now that we have generated all of the strings, we can allocate out_buf.
552 // 537 //
553 *out_len = NTLM_TYPE3_HEADER_LEN + host_len + domain_len + user_len + 538 *out_len = NTLM_TYPE3_HEADER_LEN + host_len + domain_len + user_len +
554 LM_RESP_LEN + NTLM_RESP_LEN; 539 LM_RESP_LEN + NTLM_RESP_LEN;
555 *out_buf = malloc(*out_len); 540 *out_buf = malloc(*out_len);
556 if (!*out_buf) 541 if (!*out_buf)
557 return ERR_OUT_OF_MEMORY; 542 return ERR_OUT_OF_MEMORY;
558 543
559 // 544 //
560 // Next, we compute the LM and NTLM responses. 545 // Next, we compute the LM and NTLM responses.
561 // 546 //
562 uint8 lm_resp[LM_RESP_LEN]; 547 uint8 lm_resp[LM_RESP_LEN];
563 uint8 ntlm_resp[NTLM_RESP_LEN]; 548 uint8 ntlm_resp[NTLM_RESP_LEN];
564 uint8 ntlm_hash[NTLM_HASH_LEN]; 549 uint8 ntlm_hash[NTLM_HASH_LEN];
565 if (msg.flags & NTLM_NegotiateNTLM2Key) { 550 if (msg.flags & NTLM_NegotiateNTLM2Key) {
566 // compute NTLM2 session response 551 // compute NTLM2 session response
567 MD5Digest session_hash; 552 MD5Digest session_hash;
568 uint8 temp[16]; 553 uint8 temp[16];
569 554
570 generate_random_proc_(lm_resp, 8); 555 memcpy(lm_resp, rand_8_bytes, 8);
571 memset(lm_resp + 8, 0, LM_RESP_LEN - 8); 556 memset(lm_resp + 8, 0, LM_RESP_LEN - 8);
572 557
573 memcpy(temp, msg.challenge, 8); 558 memcpy(temp, msg.challenge, 8);
574 memcpy(temp + 8, lm_resp, 8); 559 memcpy(temp + 8, lm_resp, 8);
575 MD5Sum(temp, 16, &session_hash); 560 MD5Sum(temp, 16, &session_hash);
576 561
577 NTLM_Hash(password, ntlm_hash); 562 NTLM_Hash(password, ntlm_hash);
578 LM_Response(ntlm_hash, session_hash.a, ntlm_resp); 563 LM_Response(ntlm_hash, session_hash.a, ntlm_resp);
579 } else { 564 } else {
580 NTLM_Hash(password, ntlm_hash); 565 NTLM_Hash(password, ntlm_hash);
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
631 616
632 // 52 : session key sec buf (not used) 617 // 52 : session key sec buf (not used)
633 cursor = WriteSecBuf(cursor, 0, 0); 618 cursor = WriteSecBuf(cursor, 0, 0);
634 619
635 // 60 : negotiated flags 620 // 60 : negotiated flags
636 cursor = WriteDWORD(cursor, msg.flags & NTLM_TYPE1_FLAGS); 621 cursor = WriteDWORD(cursor, msg.flags & NTLM_TYPE1_FLAGS);
637 622
638 return OK; 623 return OK;
639 } 624 }
640 625
641 //-----------------------------------------------------------------------------
642
643 class NTLMAuthModule {
644 public:
645 NTLMAuthModule() {}
646
647 ~NTLMAuthModule();
648
649 int Init(const string16& domain,
650 const string16& username,
651 const string16& password);
652
653 int GetNextToken(const void* in_token,
654 uint32 in_token_len,
655 void** out_token,
656 uint32* out_token_len);
657
658 private:
659 string16 domain_;
660 string16 username_;
661 string16 password_;
662 };
663
664 NTLMAuthModule::~NTLMAuthModule() {
665 ZapString(&password_);
666 }
667
668 int NTLMAuthModule::Init(const string16& domain,
669 const string16& username,
670 const string16& password) {
671 domain_ = domain;
672 username_ = username;
673 password_ = password;
674 return OK;
675 }
676
677 int NTLMAuthModule::GetNextToken(const void* in_token,
678 uint32 in_token_len,
679 void** out_token,
680 uint32* out_token_len) {
681 int rv;
682
683 // If in_token is non-null, then assume it contains a type 2 message...
684 if (in_token) {
685 LogToken("in-token", in_token, in_token_len);
686 rv = GenerateType3Msg(domain_, username_, password_, in_token,
687 in_token_len, out_token, out_token_len);
688 } else {
689 rv = GenerateType1Msg(out_token, out_token_len);
690 }
691
692 if (rv == OK)
693 LogToken("out-token", *out_token, *out_token_len);
694
695 return rv;
696 }
697
698 // NTLM authentication is specified in "NTLM Over HTTP Protocol Specification" 626 // NTLM authentication is specified in "NTLM Over HTTP Protocol Specification"
699 // [MS-NTHT]. 627 // [MS-NTHT].
700 628
701 HttpAuthHandlerNTLM::HttpAuthHandlerNTLM() 629 // static
702 : ntlm_module_(new NTLMAuthModule) { 630 HttpAuthHandlerNTLM::GenerateRandomProc
631 HttpAuthHandlerNTLM::generate_random_proc_ = GenerateRandom;
632
633 // static
634 HttpAuthHandlerNTLM::HostNameProc
635 HttpAuthHandlerNTLM::get_host_name_proc_ = GetMyHostName;
636
637 HttpAuthHandlerNTLM::HttpAuthHandlerNTLM() {
703 } 638 }
704 639
705 HttpAuthHandlerNTLM::~HttpAuthHandlerNTLM() { 640 HttpAuthHandlerNTLM::~HttpAuthHandlerNTLM() {
641 // Wipe our copy of the password from memory, to reduce the chance of being
642 // written to the paging file on disk.
643 ZapString(&password_);
706 } 644 }
707 645
708 bool HttpAuthHandlerNTLM::NeedsIdentity() { 646 bool HttpAuthHandlerNTLM::NeedsIdentity() {
709 return !auth_data_.empty(); 647 return !auth_data_.empty();
710 } 648 }
711 649
712 std::string HttpAuthHandlerNTLM::GenerateCredentials( 650 std::string HttpAuthHandlerNTLM::GenerateCredentials(
713 const std::wstring& username, 651 const std::wstring& username,
714 const std::wstring& password, 652 const std::wstring& password,
715 const HttpRequestInfo* request, 653 const HttpRequestInfo* request,
716 const ProxyInfo* proxy) { 654 const ProxyInfo* proxy) {
717 int rv;
718 // TODO(wtc): See if we can use char* instead of void* for in_buf and 655 // TODO(wtc): See if we can use char* instead of void* for in_buf and
719 // out_buf. This change will need to propagate to GetNextToken, 656 // out_buf. This change will need to propagate to GetNextToken,
720 // GenerateType1Msg, and GenerateType3Msg, and perhaps further. 657 // GenerateType1Msg, and GenerateType3Msg, and perhaps further.
721 const void* in_buf; 658 const void* in_buf;
722 void* out_buf; 659 void* out_buf;
723 uint32 in_buf_len, out_buf_len; 660 uint32 in_buf_len, out_buf_len;
724 std::string decoded_auth_data; 661 std::string decoded_auth_data;
725 662
726 // |username| may be in the form "DOMAIN\user". Parse it into the two 663 // |username| may be in the form "DOMAIN\user". Parse it into the two
727 // components. 664 // components.
728 std::wstring domain; 665 std::wstring domain;
729 std::wstring user; 666 std::wstring user;
730 size_t backslash_idx = username.find(L'\\'); 667 size_t backslash_idx = username.find(L'\\');
731 if (backslash_idx == std::wstring::npos) { 668 if (backslash_idx == std::wstring::npos) {
732 user = username; 669 user = username;
733 } else { 670 } else {
734 domain = username.substr(0, backslash_idx); 671 domain = username.substr(0, backslash_idx);
735 user = username.substr(backslash_idx + 1); 672 user = username.substr(backslash_idx + 1);
736 } 673 }
737 rv = ntlm_module_->Init(WideToUTF16(domain), WideToUTF16(user), 674 domain_ = WideToUTF16(domain);
738 WideToUTF16(password)); 675 username_ = WideToUTF16(user);
676 password_ = WideToUTF16(password);
739 677
740 // Initial challenge. 678 // Initial challenge.
741 if (auth_data_.empty()) { 679 if (auth_data_.empty()) {
742 in_buf_len = 0; 680 in_buf_len = 0;
743 in_buf = NULL; 681 in_buf = NULL;
744 } else { 682 } else {
745 // Decode |auth_data_| into the input buffer. 683 // Decode |auth_data_| into the input buffer.
746 int len = auth_data_.length(); 684 int len = auth_data_.length();
747 685
748 // Strip off any padding. 686 // Strip off any padding.
749 // (See https://bugzilla.mozilla.org/show_bug.cgi?id=230351.) 687 // (See https://bugzilla.mozilla.org/show_bug.cgi?id=230351.)
750 // 688 //
751 // Our base64 decoder requires that the length be a multiple of 4. 689 // Our base64 decoder requires that the length be a multiple of 4.
752 while (len > 0 && len % 4 != 0 && auth_data_[len - 1] == '=') 690 while (len > 0 && len % 4 != 0 && auth_data_[len - 1] == '=')
753 len--; 691 len--;
754 auth_data_.erase(len); 692 auth_data_.erase(len);
755 693
756 if (!Base64Decode(auth_data_, &decoded_auth_data)) 694 if (!Base64Decode(auth_data_, &decoded_auth_data))
757 return std::string(); // Improper base64 encoding 695 return std::string(); // Improper base64 encoding
758 in_buf_len = decoded_auth_data.length(); 696 in_buf_len = decoded_auth_data.length();
759 in_buf = decoded_auth_data.data(); 697 in_buf = decoded_auth_data.data();
760 } 698 }
761 699
762 rv = ntlm_module_->GetNextToken(in_buf, in_buf_len, &out_buf, &out_buf_len); 700 int rv = GetNextToken(in_buf, in_buf_len, &out_buf, &out_buf_len);
763 if (rv != OK) 701 if (rv != OK)
764 return std::string(); 702 return std::string();
765 703
766 // Base64 encode data in output buffer and prepend "NTLM ". 704 // Base64 encode data in output buffer and prepend "NTLM ".
767 std::string encode_input(static_cast<char*>(out_buf), out_buf_len); 705 std::string encode_input(static_cast<char*>(out_buf), out_buf_len);
768 std::string encode_output; 706 std::string encode_output;
769 bool ok = Base64Encode(encode_input, &encode_output); 707 bool ok = Base64Encode(encode_input, &encode_output);
770 // OK, we are done with |out_buf| 708 // OK, we are done with |out_buf|
771 free(out_buf); 709 free(out_buf);
772 if (!ok) 710 if (!ok)
773 return std::string(); 711 return std::string();
774 return std::string("NTLM ") + encode_output; 712 return std::string("NTLM ") + encode_output;
775 } 713 }
776 714
777 // static 715 // static
778 void HttpAuthHandlerNTLM::SetGenerateRandomProc(GenerateRandomProc proc) { 716 HttpAuthHandlerNTLM::GenerateRandomProc
717 HttpAuthHandlerNTLM::SetGenerateRandomProc(
718 GenerateRandomProc proc) {
719 GenerateRandomProc old_proc = generate_random_proc_;
779 generate_random_proc_ = proc; 720 generate_random_proc_ = proc;
721 return old_proc;
780 } 722 }
781 723
782 // static 724 // static
783 void HttpAuthHandlerNTLM::SetHostNameProc(HostNameProc proc) { 725 HttpAuthHandlerNTLM::HostNameProc HttpAuthHandlerNTLM::SetHostNameProc(
726 HostNameProc proc) {
727 HostNameProc old_proc = get_host_name_proc_;
784 get_host_name_proc_ = proc; 728 get_host_name_proc_ = proc;
729 return old_proc;
785 } 730 }
786 731
787 // The NTLM challenge header looks like: 732 // The NTLM challenge header looks like:
788 // WWW-Authenticate: NTLM auth-data 733 // WWW-Authenticate: NTLM auth-data
789 bool HttpAuthHandlerNTLM::ParseChallenge( 734 bool HttpAuthHandlerNTLM::ParseChallenge(
790 std::string::const_iterator challenge_begin, 735 std::string::const_iterator challenge_begin,
791 std::string::const_iterator challenge_end) { 736 std::string::const_iterator challenge_end) {
792 scheme_ = "ntlm"; 737 scheme_ = "ntlm";
793 score_ = 3; 738 score_ = 3;
794 properties_ = ENCRYPTS_IDENTITY | IS_CONNECTION_BASED; 739 properties_ = ENCRYPTS_IDENTITY | IS_CONNECTION_BASED;
795 auth_data_.clear(); 740 auth_data_.clear();
796 741
797 // Verify the challenge's auth-scheme. 742 // Verify the challenge's auth-scheme.
798 HttpAuth::ChallengeTokenizer challenge_tok(challenge_begin, challenge_end); 743 HttpAuth::ChallengeTokenizer challenge_tok(challenge_begin, challenge_end);
799 if (!challenge_tok.valid() || 744 if (!challenge_tok.valid() ||
800 !LowerCaseEqualsASCII(challenge_tok.scheme(), "ntlm")) 745 !LowerCaseEqualsASCII(challenge_tok.scheme(), "ntlm"))
801 return false; 746 return false;
802 747
803 // Extract the auth-data. We can't use challenge_tok.GetNext() because 748 // Extract the auth-data. We can't use challenge_tok.GetNext() because
804 // auth-data is base64-encoded and may contain '=' padding at the end, 749 // auth-data is base64-encoded and may contain '=' padding at the end,
805 // which would be mistaken for a name=value pair. 750 // which would be mistaken for a name=value pair.
806 challenge_begin += 4; // Skip over "NTLM". 751 challenge_begin += 4; // Skip over "NTLM".
807 HttpUtil::TrimLWS(&challenge_begin, &challenge_end); 752 HttpUtil::TrimLWS(&challenge_begin, &challenge_end);
808 753
809 auth_data_.assign(challenge_begin, challenge_end); 754 auth_data_.assign(challenge_begin, challenge_end);
810 755
811 return true; 756 return true;
812 } 757 }
813 758
759 int HttpAuthHandlerNTLM::GetNextToken(const void* in_token,
760 uint32 in_token_len,
761 void** out_token,
762 uint32* out_token_len) {
763 int rv;
764
765 // If in_token is non-null, then assume it contains a type 2 message...
766 if (in_token) {
767 LogToken("in-token", in_token, in_token_len);
768 std::string hostname = get_host_name_proc_();
769 if (hostname.empty())
770 return ERR_UNEXPECTED;
771 uint8 rand_buf[8];
772 generate_random_proc_(rand_buf, 8);
773 rv = GenerateType3Msg(domain_, username_, password_, hostname, rand_buf,
774 in_token, in_token_len, out_token, out_token_len);
775 } else {
776 rv = GenerateType1Msg(out_token, out_token_len);
777 }
778
779 if (rv == OK)
780 LogToken("out-token", *out_token, *out_token_len);
781
782 return rv;
783 }
784
814 } // namespace net 785 } // namespace net
OLDNEW
« no previous file with comments | « net/http/http_auth_handler_ntlm.h ('k') | net/http/http_network_transaction_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698