OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/base64.h" |
15 #include "base/md5.h" | 16 #include "base/md5.h" |
| 17 #include "base/process/kill.h" |
| 18 #include "base/process/launch.h" |
16 #include "base/rand_util.h" | 19 #include "base/rand_util.h" |
17 #include "base/strings/string_util.h" | 20 #include "base/strings/string_util.h" |
18 #include "base/strings/sys_string_conversions.h" | 21 #include "base/strings/sys_string_conversions.h" |
19 #include "base/strings/utf_string_conversions.h" | 22 #include "base/strings/utf_string_conversions.h" |
20 #include "net/base/net_errors.h" | 23 #include "net/base/net_errors.h" |
21 #include "net/base/net_util.h" | 24 #include "net/base/net_util.h" |
22 #include "net/base/zap.h" | 25 #include "net/base/zap.h" |
23 #include "net/http/des.h" | 26 #include "net/http/des.h" |
24 #include "net/http/md4.h" | 27 #include "net/http/md4.h" |
25 | 28 |
(...skipping 598 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
624 // [MS-NTHT]. | 627 // [MS-NTHT]. |
625 | 628 |
626 // static | 629 // static |
627 HttpAuthHandlerNTLM::GenerateRandomProc | 630 HttpAuthHandlerNTLM::GenerateRandomProc |
628 HttpAuthHandlerNTLM::generate_random_proc_ = GenerateRandom; | 631 HttpAuthHandlerNTLM::generate_random_proc_ = GenerateRandom; |
629 | 632 |
630 // static | 633 // static |
631 HttpAuthHandlerNTLM::HostNameProc | 634 HttpAuthHandlerNTLM::HostNameProc |
632 HttpAuthHandlerNTLM::get_host_name_proc_ = GetHostName; | 635 HttpAuthHandlerNTLM::get_host_name_proc_ = GetHostName; |
633 | 636 |
634 HttpAuthHandlerNTLM::HttpAuthHandlerNTLM() { | 637 HttpAuthHandlerNTLM::HttpAuthHandlerNTLM( |
| 638 URLSecurityManager* url_security_manager) |
| 639 : url_security_manager_(url_security_manager) { |
| 640 helpername_ = getenv("CHROME_NTLM_USER_HELPER"); |
| 641 if (!helpername_) |
| 642 helpername_ = "/usr/bin/ntlm_auth"; |
| 643 try_winbind_ = !access(helpername_, X_OK); |
| 644 ntlm_write_pipe_ = -1; |
| 645 ntlm_read_pipe_ = -1; |
| 646 ntlm_auth_handle_ = -1; |
635 } | 647 } |
636 | 648 |
637 bool HttpAuthHandlerNTLM::NeedsIdentity() { | 649 bool HttpAuthHandlerNTLM::NeedsIdentity() { |
638 // This gets called for each round-trip. Only require identity on | 650 // If we think winbind might be available, return true on the first phase |
639 // the first call (when auth_data_ is empty). On subsequent calls, | 651 // (when auth_data_ is empty) so that the default identity gets selected. |
640 // we use the initially established identity. | 652 // If it's *not* available, then only return true on the second phase. |
641 return auth_data_.empty(); | 653 // This works even for the case where winbind *might* be available, but |
| 654 // turns out not to be when we actually get round to checking for it. |
| 655 // In that case, we'll send the portable challenge in the first phase |
| 656 // after we realise winbind can't help us, and then get a real identity |
| 657 // in time for the second phase. |
| 658 return !try_winbind_ ^ auth_data_.empty(); |
| 659 } |
| 660 |
| 661 bool HttpAuthHandlerNTLM::start_ntlm_helper_() { |
| 662 /* fork_ntlm_auth_with_pipes(); */ |
| 663 int writepipe[2] = {-1, -1}; /* parent -> child */ |
| 664 int readpipe [2] = {-1, -1}; /* child -> parent */ |
| 665 |
| 666 if ( pipe(readpipe) < 0 || pipe(writepipe) < 0 ) |
| 667 { |
| 668 VLOG(1) << "Failed to open pipes for ntlm_auth helper"; |
| 669 return false; |
| 670 } |
| 671 char *username = getenv("NTLMUSER"); |
| 672 if (!username) |
| 673 username = getenv("USER"); |
| 674 if (!username) { |
| 675 VLOG(1) << "No username. No automatic NTLM"; |
| 676 return false; |
| 677 } |
| 678 |
| 679 std::vector<std::string> args; |
| 680 base::LaunchOptions options; |
| 681 base::FileHandleMappingVector fds_to_remap; |
| 682 |
| 683 args.push_back(helpername_); |
| 684 args.push_back("--helper-protocol"); |
| 685 args.push_back("ntlmssp-client-1"); |
| 686 args.push_back("--use-cached-creds"); |
| 687 args.push_back("--username"); |
| 688 args.push_back(username); |
| 689 |
| 690 fds_to_remap.push_back(std::make_pair(readpipe[1], 1)); |
| 691 fds_to_remap.push_back(std::make_pair(writepipe[0], 0)); |
| 692 |
| 693 |
| 694 options.wait = false; |
| 695 options.fds_to_remap = &fds_to_remap; |
| 696 |
| 697 if (base::LaunchProcess(args, options, &ntlm_auth_handle_) == false) { |
| 698 VLOG(1) << "Failed to launch ntlm_auth helper"; |
| 699 close(writepipe[0]); |
| 700 close(writepipe[1]); |
| 701 close(readpipe[0]); |
| 702 close(readpipe[1]); |
| 703 return false; |
| 704 } |
| 705 ntlm_write_pipe_ = writepipe[1]; |
| 706 close(writepipe[0]); |
| 707 |
| 708 ntlm_read_pipe_ = readpipe[0]; |
| 709 close(readpipe[1]); |
| 710 |
| 711 if (write(ntlm_write_pipe_, "YR\n", 3) != 3) { |
| 712 VLOG(1) << "Failed to send YR to ntlm_auth: " << strerror(errno); |
| 713 return false; |
| 714 } |
| 715 return true; |
| 716 } |
| 717 |
| 718 void HttpAuthHandlerNTLM::OnFileCanWriteWithoutBlocking(int fd) { |
| 719 NOTREACHED(); |
| 720 } |
| 721 |
| 722 static bool read_line(int fd, char *buf, int len) { |
| 723 |
| 724 while (len) { |
| 725 int result = read(fd, buf, len); |
| 726 if (result <= 0) |
| 727 return false; |
| 728 else { |
| 729 if (buf[result - 1] == '\n') { |
| 730 buf[result - 1] = 0; |
| 731 return true; |
| 732 } |
| 733 buf += result; |
| 734 len -= result; |
| 735 } |
| 736 } |
| 737 return false; |
| 738 } |
| 739 |
| 740 void HttpAuthHandlerNTLM::OnFileCanReadWithoutBlocking(int fd) { |
| 741 |
| 742 char buf[1024]; |
| 743 if (!read_line(ntlm_read_pipe_, buf, sizeof(buf))) { |
| 744 VLOG(1) << "Read initial response from ntlm_auth failed"; |
| 745 fall_back_to_portable: |
| 746 void *out_buf; |
| 747 uint32 out_buf_len; |
| 748 |
| 749 int rv = GenerateType1Msg(&out_buf, &out_buf_len); |
| 750 if (rv != OK) { |
| 751 token_callback_.Run(rv); |
| 752 return; |
| 753 } |
| 754 |
| 755 // Base64 encode data in output buffer and prepend "NTLM ". |
| 756 std::string encode_input(static_cast<char*>(out_buf), out_buf_len); |
| 757 std::string encode_output; |
| 758 base::Base64Encode(encode_input, &encode_output); |
| 759 // OK, we are done with |out_buf| |
| 760 free(out_buf); |
| 761 *callback_auth_token_ = std::string("NTLM ") + encode_output; |
| 762 |
| 763 token_callback_.Run(OK); |
| 764 ntlm_read_watcher_.StopWatchingFileDescriptor(); |
| 765 try_winbind_ = false; |
| 766 return; |
| 767 } |
| 768 if (!strcmp(buf, "PW")) { |
| 769 VLOG(1) << "ntlm_auth asks for password"; |
| 770 goto fall_back_to_portable; |
| 771 } |
| 772 if (strncmp(buf, "YR ", 3) && strncmp(buf, "KK ", 3) && |
| 773 strncmp(buf, "AF ", 3)) { |
| 774 VLOG(1) << "Unknown response from ntlm_auth: " << buf; |
| 775 goto fall_back_to_portable; |
| 776 } |
| 777 |
| 778 VLOG(1) << "Yay, ntlm_auth gives challenge: " << buf; |
| 779 *callback_auth_token_ = std::string("NTLM ") + std::string(buf + 3); |
| 780 return token_callback_.Run(OK); |
642 } | 781 } |
643 | 782 |
644 bool HttpAuthHandlerNTLM::AllowsDefaultCredentials() { | 783 bool HttpAuthHandlerNTLM::AllowsDefaultCredentials() { |
645 // Default credentials are not supported in the portable implementation of | 784 // Always return true (assuning the UrlSecurityManager permits it) if |
646 // NTLM, but are supported in the SSPI implementation. | 785 // it looks like the winbind helper even might be available; we can't |
647 return false; | 786 // check properly yet because we need to do that asynchronously. |
| 787 if (!try_winbind_) |
| 788 return false; |
| 789 if (target_ == HttpAuth::AUTH_PROXY) |
| 790 return true; |
| 791 if (!url_security_manager_) |
| 792 return false; |
| 793 return url_security_manager_->CanUseDefaultCredentials(origin_); |
648 } | 794 } |
649 | 795 |
650 int HttpAuthHandlerNTLM::InitializeBeforeFirstChallenge() { | 796 int HttpAuthHandlerNTLM::InitializeBeforeFirstChallenge() { |
651 return OK; | 797 return OK; |
652 } | 798 } |
653 | 799 |
654 HttpAuthHandlerNTLM::~HttpAuthHandlerNTLM() { | 800 HttpAuthHandlerNTLM::~HttpAuthHandlerNTLM() { |
655 credentials_.Zap(); | 801 credentials_.Zap(); |
| 802 if (ntlm_write_pipe_ != -1) |
| 803 close(ntlm_write_pipe_); |
| 804 if (ntlm_read_pipe_ != -1) |
| 805 close(ntlm_read_pipe_); |
| 806 if (ntlm_auth_handle_ != -1) |
| 807 base::KillProcess(ntlm_auth_handle_, 1, true); |
656 } | 808 } |
657 | 809 |
658 // static | 810 // static |
659 HttpAuthHandlerNTLM::GenerateRandomProc | 811 HttpAuthHandlerNTLM::GenerateRandomProc |
660 HttpAuthHandlerNTLM::SetGenerateRandomProc( | 812 HttpAuthHandlerNTLM::SetGenerateRandomProc( |
661 GenerateRandomProc proc) { | 813 GenerateRandomProc proc) { |
662 GenerateRandomProc old_proc = generate_random_proc_; | 814 GenerateRandomProc old_proc = generate_random_proc_; |
663 generate_random_proc_ = proc; | 815 generate_random_proc_ = proc; |
664 return old_proc; | 816 return old_proc; |
665 } | 817 } |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
713 CreateReason reason, | 865 CreateReason reason, |
714 int digest_nonce_count, | 866 int digest_nonce_count, |
715 const BoundNetLog& net_log, | 867 const BoundNetLog& net_log, |
716 scoped_ptr<HttpAuthHandler>* handler) { | 868 scoped_ptr<HttpAuthHandler>* handler) { |
717 if (reason == CREATE_PREEMPTIVE) | 869 if (reason == CREATE_PREEMPTIVE) |
718 return ERR_UNSUPPORTED_AUTH_SCHEME; | 870 return ERR_UNSUPPORTED_AUTH_SCHEME; |
719 // TODO(cbentzel): Move towards model of parsing in the factory | 871 // TODO(cbentzel): Move towards model of parsing in the factory |
720 // method and only constructing when valid. | 872 // method and only constructing when valid. |
721 // NOTE: Default credentials are not supported for the portable implementation | 873 // NOTE: Default credentials are not supported for the portable implementation |
722 // of NTLM. | 874 // of NTLM. |
723 scoped_ptr<HttpAuthHandler> tmp_handler(new HttpAuthHandlerNTLM); | 875 scoped_ptr<HttpAuthHandler> tmp_handler( |
| 876 new HttpAuthHandlerNTLM(url_security_manager())); |
724 if (!tmp_handler->InitFromChallenge(challenge, target, origin, net_log)) | 877 if (!tmp_handler->InitFromChallenge(challenge, target, origin, net_log)) |
725 return ERR_INVALID_RESPONSE; | 878 return ERR_INVALID_RESPONSE; |
726 handler->swap(tmp_handler); | 879 handler->swap(tmp_handler); |
727 return OK; | 880 return OK; |
728 } | 881 } |
729 | 882 |
730 } // namespace net | 883 } // namespace net |
OLD | NEW |