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

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

Issue 388063005: Add NTLM single-sign-on support via Samba's ntlm_auth helper Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Review feedback Created 6 years, 4 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
« no previous file with comments | « net/http/http_auth_handler_ntlm.cc ('k') | no next file » | 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) 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
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
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
OLDNEW
« no previous file with comments | « net/http/http_auth_handler_ntlm.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698