| Index: net/http/http_auth_handler_ntlm_portable.cc
|
| diff --git a/net/http/http_auth_handler_ntlm_portable.cc b/net/http/http_auth_handler_ntlm_portable.cc
|
| index 035a6dc80170c091536c615c49c013332ce13b73..d38228cc58af416b039c79ae1d1ac91e8baf9dfc 100644
|
| --- a/net/http/http_auth_handler_ntlm_portable.cc
|
| +++ b/net/http/http_auth_handler_ntlm_portable.cc
|
| @@ -12,7 +12,10 @@
|
| #include <winsock2.h>
|
| #endif
|
|
|
| +#include "base/base64.h"
|
| #include "base/md5.h"
|
| +#include "base/process/kill.h"
|
| +#include "base/process/launch.h"
|
| #include "base/rand_util.h"
|
| #include "base/strings/string_util.h"
|
| #include "base/strings/sys_string_conversions.h"
|
| @@ -631,28 +634,177 @@ HttpAuthHandlerNTLM::generate_random_proc_ = GenerateRandom;
|
| HttpAuthHandlerNTLM::HostNameProc
|
| HttpAuthHandlerNTLM::get_host_name_proc_ = GetHostName;
|
|
|
| -HttpAuthHandlerNTLM::HttpAuthHandlerNTLM() {
|
| +HttpAuthHandlerNTLM::HttpAuthHandlerNTLM(
|
| + URLSecurityManager* url_security_manager)
|
| + : url_security_manager_(url_security_manager) {
|
| + helpername_ = getenv("CHROME_NTLM_USER_HELPER");
|
| + if (!helpername_)
|
| + helpername_ = "/usr/bin/ntlm_auth";
|
| + try_winbind_ = !access(helpername_, X_OK);
|
| + ntlm_write_pipe_ = -1;
|
| + ntlm_read_pipe_ = -1;
|
| + ntlm_auth_handle_ = -1;
|
| }
|
|
|
| bool HttpAuthHandlerNTLM::NeedsIdentity() {
|
| - // This gets called for each round-trip. Only require identity on
|
| - // the first call (when auth_data_ is empty). On subsequent calls,
|
| - // we use the initially established identity.
|
| - return auth_data_.empty();
|
| + // If we think winbind might be available, return true on the first phase
|
| + // (when auth_data_ is empty) so that the default identity gets selected.
|
| + // If it's *not* available, then only return true on the second phase.
|
| + // This works even for the case where winbind *might* be available, but
|
| + // turns out not to be when we actually get round to checking for it.
|
| + // In that case, we'll send the portable challenge in the first phase
|
| + // after we realise winbind can't help us, and then get a real identity
|
| + // in time for the second phase.
|
| + return !try_winbind_ ^ auth_data_.empty();
|
| }
|
|
|
| -bool HttpAuthHandlerNTLM::AllowsDefaultCredentials() {
|
| - // Default credentials are not supported in the portable implementation of
|
| - // NTLM, but are supported in the SSPI implementation.
|
| +bool HttpAuthHandlerNTLM::start_ntlm_helper_() {
|
| + /* fork_ntlm_auth_with_pipes(); */
|
| + int writepipe[2] = {-1, -1}; /* parent -> child */
|
| + int readpipe [2] = {-1, -1}; /* child -> parent */
|
| +
|
| + if ( pipe(readpipe) < 0 || pipe(writepipe) < 0 )
|
| + {
|
| + VLOG(1) << "Failed to open pipes for ntlm_auth helper";
|
| + return false;
|
| + }
|
| + char *username = getenv("NTLMUSER");
|
| + if (!username)
|
| + username = getenv("USER");
|
| + if (!username) {
|
| + VLOG(1) << "No username. No automatic NTLM";
|
| + return false;
|
| + }
|
| +
|
| + std::vector<std::string> args;
|
| + base::LaunchOptions options;
|
| + base::FileHandleMappingVector fds_to_remap;
|
| +
|
| + args.push_back(helpername_);
|
| + args.push_back("--helper-protocol");
|
| + args.push_back("ntlmssp-client-1");
|
| + args.push_back("--use-cached-creds");
|
| + args.push_back("--username");
|
| + args.push_back(username);
|
| +
|
| + fds_to_remap.push_back(std::make_pair(readpipe[1], 1));
|
| + fds_to_remap.push_back(std::make_pair(writepipe[0], 0));
|
| +
|
| +
|
| + options.wait = false;
|
| + options.fds_to_remap = &fds_to_remap;
|
| +
|
| + if (base::LaunchProcess(args, options, &ntlm_auth_handle_) == false) {
|
| + VLOG(1) << "Failed to launch ntlm_auth helper";
|
| + close(writepipe[0]);
|
| + close(writepipe[1]);
|
| + close(readpipe[0]);
|
| + close(readpipe[1]);
|
| + return false;
|
| + }
|
| + ntlm_write_pipe_ = writepipe[1];
|
| + close(writepipe[0]);
|
| +
|
| + ntlm_read_pipe_ = readpipe[0];
|
| + close(readpipe[1]);
|
| +
|
| + if (write(ntlm_write_pipe_, "YR\n", 3) != 3) {
|
| + VLOG(1) << "Failed to send YR to ntlm_auth: " << strerror(errno);
|
| + return false;
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +void HttpAuthHandlerNTLM::OnFileCanWriteWithoutBlocking(int fd) {
|
| + NOTREACHED();
|
| +}
|
| +
|
| +static bool read_line(int fd, char *buf, int len) {
|
| +
|
| + while (len) {
|
| + int result = read(fd, buf, len);
|
| + if (result <= 0)
|
| + return false;
|
| + else {
|
| + if (buf[result - 1] == '\n') {
|
| + buf[result - 1] = 0;
|
| + return true;
|
| + }
|
| + buf += result;
|
| + len -= result;
|
| + }
|
| + }
|
| return false;
|
| }
|
|
|
| +void HttpAuthHandlerNTLM::OnFileCanReadWithoutBlocking(int fd) {
|
| +
|
| + char buf[1024];
|
| + if (!read_line(ntlm_read_pipe_, buf, sizeof(buf))) {
|
| + VLOG(1) << "Read initial response from ntlm_auth failed";
|
| + fall_back_to_portable:
|
| + void *out_buf;
|
| + uint32 out_buf_len;
|
| +
|
| + int rv = GenerateType1Msg(&out_buf, &out_buf_len);
|
| + if (rv != OK) {
|
| + token_callback_.Run(rv);
|
| + return;
|
| + }
|
| +
|
| + // Base64 encode data in output buffer and prepend "NTLM ".
|
| + std::string encode_input(static_cast<char*>(out_buf), out_buf_len);
|
| + std::string encode_output;
|
| + base::Base64Encode(encode_input, &encode_output);
|
| + // OK, we are done with |out_buf|
|
| + free(out_buf);
|
| + *callback_auth_token_ = std::string("NTLM ") + encode_output;
|
| +
|
| + token_callback_.Run(OK);
|
| + ntlm_read_watcher_.StopWatchingFileDescriptor();
|
| + try_winbind_ = false;
|
| + return;
|
| + }
|
| + if (!strcmp(buf, "PW")) {
|
| + VLOG(1) << "ntlm_auth asks for password";
|
| + goto fall_back_to_portable;
|
| + }
|
| + if (strncmp(buf, "YR ", 3) && strncmp(buf, "KK ", 3) &&
|
| + strncmp(buf, "AF ", 3)) {
|
| + VLOG(1) << "Unknown response from ntlm_auth: " << buf;
|
| + goto fall_back_to_portable;
|
| + }
|
| +
|
| + VLOG(1) << "Yay, ntlm_auth gives challenge: " << buf;
|
| + *callback_auth_token_ = std::string("NTLM ") + std::string(buf + 3);
|
| + return token_callback_.Run(OK);
|
| +}
|
| +
|
| +bool HttpAuthHandlerNTLM::AllowsDefaultCredentials() {
|
| + // Always return true (assuning the UrlSecurityManager permits it) if
|
| + // it looks like the winbind helper even might be available; we can't
|
| + // check properly yet because we need to do that asynchronously.
|
| + if (!try_winbind_)
|
| + return false;
|
| + if (target_ == HttpAuth::AUTH_PROXY)
|
| + return true;
|
| + if (!url_security_manager_)
|
| + return false;
|
| + return url_security_manager_->CanUseDefaultCredentials(origin_);
|
| +}
|
| +
|
| int HttpAuthHandlerNTLM::InitializeBeforeFirstChallenge() {
|
| return OK;
|
| }
|
|
|
| HttpAuthHandlerNTLM::~HttpAuthHandlerNTLM() {
|
| credentials_.Zap();
|
| + if (ntlm_write_pipe_ != -1)
|
| + close(ntlm_write_pipe_);
|
| + if (ntlm_read_pipe_ != -1)
|
| + close(ntlm_read_pipe_);
|
| + if (ntlm_auth_handle_ != -1)
|
| + base::KillProcess(ntlm_auth_handle_, 1, true);
|
| }
|
|
|
| // static
|
| @@ -720,7 +872,8 @@ int HttpAuthHandlerNTLM::Factory::CreateAuthHandler(
|
| // method and only constructing when valid.
|
| // NOTE: Default credentials are not supported for the portable implementation
|
| // of NTLM.
|
| - scoped_ptr<HttpAuthHandler> tmp_handler(new HttpAuthHandlerNTLM);
|
| + scoped_ptr<HttpAuthHandler> tmp_handler(
|
| + new HttpAuthHandlerNTLM(url_security_manager()));
|
| if (!tmp_handler->InitFromChallenge(challenge, target, origin, net_log))
|
| return ERR_INVALID_RESPONSE;
|
| handler->swap(tmp_handler);
|
|
|