Index: chrome/browser/chromeos/login/parallel_authenticator.cc |
diff --git a/chrome/browser/chromeos/login/parallel_authenticator.cc b/chrome/browser/chromeos/login/parallel_authenticator.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..45192173049135644c2bbc1e48ec92835a42898d |
--- /dev/null |
+++ b/chrome/browser/chromeos/login/parallel_authenticator.cc |
@@ -0,0 +1,635 @@ |
+// Copyright (c) 2010 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "chrome/browser/chromeos/login/parallel_authenticator.h" |
+ |
+#include <string> |
+#include <vector> |
+ |
+#include "base/file_path.h" |
+#include "base/file_util.h" |
+#include "base/lock.h" |
+#include "base/logging.h" |
+#include "base/path_service.h" |
+#include "base/sha2.h" |
+#include "base/string_util.h" |
+#include "base/third_party/nss/blapi.h" |
+#include "base/third_party/nss/sha256.h" |
+#include "chrome/browser/browser_process.h" |
+#include "chrome/browser/chrome_thread.h" |
+#include "chrome/browser/chromeos/cros/cryptohome_library.h" |
+#include "chrome/browser/chromeos/login/auth_response_handler.h" |
+#include "chrome/browser/chromeos/login/authentication_notification_details.h" |
+#include "chrome/browser/chromeos/login/login_status_consumer.h" |
+#include "chrome/browser/chromeos/login/ownership_service.h" |
+#include "chrome/browser/profile.h" |
+#include "chrome/browser/profile_manager.h" |
+#include "chrome/common/chrome_paths.h" |
+#include "chrome/common/net/gaia/gaia_authenticator2.h" |
+#include "chrome/common/net/gaia/gaia_constants.h" |
+#include "chrome/common/notification_service.h" |
+#include "net/base/load_flags.h" |
+#include "net/base/net_errors.h" |
+#include "net/url_request/url_request_status.h" |
+#include "third_party/libjingle/source/talk/base/urlencode.h" |
+ |
+using base::Time; |
+using base::TimeDelta; |
+using file_util::GetFileSize; |
+using file_util::PathExists; |
+using file_util::ReadFile; |
+using file_util::ReadFileToString; |
+ |
+namespace chromeos { |
+ |
+// static |
+const char ParallelAuthenticator::kLocalaccountFile[] = "localaccount"; |
+ |
+// static |
+const int ParallelAuthenticator::kClientLoginTimeoutMs = 10000; |
+// static |
+const int ParallelAuthenticator::kLocalaccountRetryIntervalMs = 20; |
+ |
+const int kPassHashLen = 32; |
+ |
+ParallelAuthenticator::ParallelAuthenticator(LoginStatusConsumer* consumer) |
+ : Authenticator(consumer), |
+ already_reported_success_(false), |
+ checked_for_localaccount_(false) { |
+ CHECK(chromeos::CrosLibrary::Get()->EnsureLoaded()); |
+ // If not already owned, this is a no-op. If it is, this loads the owner's |
+ // public key off of disk. |
+ OwnershipService::GetSharedInstance()->StartLoadOwnerKeyAttempt(); |
+} |
+ |
+ParallelAuthenticator::~ParallelAuthenticator() {} |
+ |
+bool ParallelAuthenticator::AuthenticateToLogin( |
+ Profile* profile, |
+ const std::string& username, |
+ const std::string& password, |
+ const std::string& login_token, |
+ const std::string& login_captcha) { |
+ current_state_.reset( |
+ new AuthAttemptState(Authenticator::Canonicalize(username), |
+ password, |
+ HashPassword(password), |
+ login_token, |
+ login_captcha)); |
+ mounter_ = CryptohomeOp::CreateMountAttempt(current_state_.get(), |
+ this, |
+ false /* don't create */); |
+ current_online_ = new OnlineAttempt(current_state_.get(), this); |
+ // Sadly, this MUST be on the UI thread due to sending DBus traffic :-/ |
+ ChromeThread::PostTask( |
+ ChromeThread::UI, FROM_HERE, |
+ NewRunnableMethod(mounter_.get(), &CryptohomeOp::Initiate)); |
+ ChromeThread::PostTask( |
+ ChromeThread::IO, FROM_HERE, |
+ NewRunnableMethod(current_online_.get(), |
+ &OnlineAttempt::Initiate, |
+ profile)); |
+ ChromeThread::PostTask( |
+ ChromeThread::FILE, FROM_HERE, |
+ NewRunnableMethod(this, |
+ &ParallelAuthenticator::LoadLocalaccount, |
+ std::string(kLocalaccountFile))); |
+ return true; |
+} |
+ |
+bool ParallelAuthenticator::AuthenticateToUnlock(const std::string& username, |
+ const std::string& password) { |
+ current_state_.reset( |
+ new AuthAttemptState(Authenticator::Canonicalize(username), |
+ HashPassword(password))); |
+ ChromeThread::PostTask( |
+ ChromeThread::FILE, FROM_HERE, |
+ NewRunnableMethod(this, |
+ &ParallelAuthenticator::LoadLocalaccount, |
+ std::string(kLocalaccountFile))); |
+ key_checker_ = CryptohomeOp::CreateCheckKeyAttempt(current_state_.get(), |
+ this); |
+ // Sadly, this MUST be on the UI thread due to sending DBus traffic :-/ |
+ ChromeThread::PostTask( |
+ ChromeThread::UI, FROM_HERE, |
+ NewRunnableMethod(key_checker_.get(), &CryptohomeOp::Initiate)); |
+ return true; |
+} |
+ |
+void ParallelAuthenticator::LoginOffTheRecord() { |
+ current_state_.reset(new AuthAttemptState("", "", "", "", "")); |
+ guest_mounter_ = |
+ CryptohomeOp::CreateMountGuestAttempt(current_state_.get(), this); |
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
+ guest_mounter_->Initiate(); |
+} |
+ |
+void ParallelAuthenticator::OnLoginSuccess( |
+ const GaiaAuthConsumer::ClientLoginResult& credentials, |
+ bool request_pending) { |
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
+ LOG(INFO) << "Online login success"; |
+ // Send notification of success |
+ AuthenticationNotificationDetails details(true); |
+ NotificationService::current()->Notify( |
+ NotificationType::LOGIN_AUTHENTICATION, |
+ NotificationService::AllSources(), |
+ Details<AuthenticationNotificationDetails>(&details)); |
+ { |
+ AutoLock for_this_block(success_lock_); |
+ already_reported_success_ = true; |
+ } |
+ consumer_->OnLoginSuccess(current_state_->username, |
+ credentials, |
+ request_pending); |
+} |
+ |
+void ParallelAuthenticator::OnOffTheRecordLoginSuccess() { |
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
+ // Send notification of success |
+ AuthenticationNotificationDetails details(true); |
+ NotificationService::current()->Notify( |
+ NotificationType::LOGIN_AUTHENTICATION, |
+ NotificationService::AllSources(), |
+ Details<AuthenticationNotificationDetails>(&details)); |
+ consumer_->OnOffTheRecordLoginSuccess(); |
+} |
+ |
+void ParallelAuthenticator::OnPasswordChangeDetected( |
+ const GaiaAuthConsumer::ClientLoginResult& credentials) { |
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
+ consumer_->OnPasswordChangeDetected(credentials); |
+} |
+ |
+void ParallelAuthenticator::CheckLocalaccount(const LoginFailure& error) { |
+ { |
+ AutoLock for_this_block(localaccount_lock_); |
+ LOG(INFO) << "Checking localaccount"; |
+ if (!checked_for_localaccount_) { |
+ ChromeThread::PostDelayedTask( |
+ ChromeThread::FILE, FROM_HERE, |
+ NewRunnableMethod(this, |
+ &ParallelAuthenticator::CheckLocalaccount, |
+ error), |
+ kLocalaccountRetryIntervalMs); |
+ return; |
+ } |
+ } |
+ |
+ if (!localaccount_.empty() && localaccount_ == current_state_->username) { |
+ // Success. Go mount a tmpfs for the profile, if necessary. |
+ if (!current_state_->unlock) { |
+ guest_mounter_ = |
+ CryptohomeOp::CreateMountGuestAttempt(current_state_.get(), this); |
+ ChromeThread::PostTask( |
+ ChromeThread::UI, FROM_HERE, |
+ NewRunnableMethod(guest_mounter_.get(), &CryptohomeOp::Initiate)); |
+ } else { |
+ ChromeThread::PostTask( |
+ ChromeThread::UI, FROM_HERE, |
+ NewRunnableMethod(this, &ParallelAuthenticator::OnLoginSuccess, |
+ GaiaAuthConsumer::ClientLoginResult(), false)); |
+ } |
+ } else { |
+ // Not the localaccount. Fail, passing along cached error info. |
+ ChromeThread::PostTask( |
+ ChromeThread::UI, FROM_HERE, |
+ NewRunnableMethod(this, &ParallelAuthenticator::OnLoginFailure, error)); |
+ } |
+} |
+ |
+void ParallelAuthenticator::OnLoginFailure(const LoginFailure& error) { |
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
+ // Send notification of failure |
+ AuthenticationNotificationDetails details(false); |
+ NotificationService::current()->Notify( |
+ NotificationType::LOGIN_AUTHENTICATION, |
+ NotificationService::AllSources(), |
+ Details<AuthenticationNotificationDetails>(&details)); |
+ LOG(WARNING) << "Login failed: " << error.GetErrorString(); |
+ consumer_->OnLoginFailure(error); |
+} |
+ |
+void ParallelAuthenticator::RecoverEncryptedData( |
+ const std::string& old_password, |
+ const GaiaAuthConsumer::ClientLoginResult& credentials) { |
+ std::string old_hash = HashPassword(old_password); |
+ key_migrator_ = CryptohomeOp::CreateMigrateAttempt(current_state_.get(), |
+ this, |
+ true, |
+ old_hash); |
+ ChromeThread::PostTask( |
+ ChromeThread::IO, FROM_HERE, |
+ NewRunnableMethod(this, |
+ &ParallelAuthenticator::ResyncRecoverHelper, |
+ key_migrator_.get())); |
+} |
+ |
+void ParallelAuthenticator::ResyncEncryptedData( |
+ const GaiaAuthConsumer::ClientLoginResult& credentials) { |
+ data_remover_ = |
+ CryptohomeOp::CreateRemoveAttempt(current_state_.get(), this); |
+ ChromeThread::PostTask( |
+ ChromeThread::IO, FROM_HERE, |
+ NewRunnableMethod(this, |
+ &ParallelAuthenticator::ResyncRecoverHelper, |
+ data_remover_.get())); |
+} |
+ |
+void ParallelAuthenticator::ResyncRecoverHelper(CryptohomeOp* to_initiate) { |
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); |
+ current_state_->ResetCryptohomeStatus(); |
+ ChromeThread::PostTask( |
+ ChromeThread::UI, FROM_HERE, |
+ NewRunnableMethod(to_initiate, &CryptohomeOp::Initiate)); |
+} |
+ |
+void ParallelAuthenticator::RetryAuth(Profile* profile, |
+ const std::string& username, |
+ const std::string& password, |
+ const std::string& login_token, |
+ const std::string& login_captcha) { |
+ reauth_state_.reset( |
+ new AuthAttemptState(Authenticator::Canonicalize(username), |
+ password, |
+ HashPassword(password), |
+ login_token, |
+ login_captcha)); |
+ current_online_ = new OnlineAttempt(reauth_state_.get(), this); |
+ ChromeThread::PostTask( |
+ ChromeThread::IO, FROM_HERE, |
+ NewRunnableMethod(current_online_.get(), |
+ &OnlineAttempt::Initiate, |
+ profile)); |
+} |
+ |
+void ParallelAuthenticator::Resolve() { |
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); |
+ bool request_pending = false; |
+ bool create = false; |
+ switch (ResolveState()) { |
+ case CONTINUE: |
+ case POSSIBLE_PW_CHANGE: |
+ case NO_MOUNT: |
+ // These are intermediate states; we need more info from a request that |
+ // is still pending. |
+ break; |
+ case FAILED_MOUNT: |
+ // In this case, whether login succeeded or not, we can't log |
+ // the user in because their data is horked. So, override with |
+ // the appropriate failure. |
+ ChromeThread::PostTask( |
+ ChromeThread::UI, FROM_HERE, |
+ NewRunnableMethod( |
+ this, |
+ &ParallelAuthenticator::OnLoginFailure, |
+ LoginFailure(LoginFailure::COULD_NOT_MOUNT_CRYPTOHOME))); |
+ break; |
+ case FAILED_REMOVE: |
+ // In this case, we tried to remove the user's old cryptohome at her |
+ // request, and the remove failed. |
+ ChromeThread::PostTask( |
+ ChromeThread::UI, FROM_HERE, |
+ NewRunnableMethod(this, &ParallelAuthenticator::OnLoginFailure, |
+ LoginFailure(LoginFailure::DATA_REMOVAL_FAILED))); |
+ break; |
+ case FAILED_TMPFS: |
+ // In this case, we tried to mount a tmpfs for BWSI or the localaccount |
+ // user and failed. |
+ ChromeThread::PostTask( |
+ ChromeThread::UI, FROM_HERE, |
+ NewRunnableMethod(this, &ParallelAuthenticator::OnLoginFailure, |
+ LoginFailure(LoginFailure::COULD_NOT_MOUNT_TMPFS))); |
+ break; |
+ case CREATE_NEW: |
+ create = true; |
+ case RECOVER_MOUNT: |
+ current_state_->ResetCryptohomeStatus(); |
+ mounter_ = CryptohomeOp::CreateMountAttempt(current_state_.get(), |
+ this, |
+ create); |
+ ChromeThread::PostTask( |
+ ChromeThread::UI, FROM_HERE, |
+ NewRunnableMethod(mounter_.get(), &CryptohomeOp::Initiate)); |
+ break; |
+ case NEED_OLD_PW: |
+ ChromeThread::PostTask( |
+ ChromeThread::UI, FROM_HERE, |
+ NewRunnableMethod(this, |
+ &ParallelAuthenticator::OnPasswordChangeDetected, |
+ current_state_->credentials())); |
+ break; |
+ case ONLINE_FAILED: |
+ // In this case, we know online login was rejected because the account |
+ // is disabled or something similarly fatal. Sending the user through |
+ // the same path they get when their password is rejected is cleaner |
+ // for now. |
+ // TODO(cmasone): optimize this so that we don't send the user through |
+ // the 'changed password' path when we know doing so won't succeed. |
+ case NEED_NEW_PW: |
+ { |
+ AutoLock for_this_block(success_lock_); |
+ if (!already_reported_success_) { |
+ // This allows us to present the same behavior for "online: |
+ // fail, offline: ok", regardless of the order in which we |
+ // receive the results. There will be cases in which we get |
+ // the online failure some time after the offline success, |
+ // so we just force all cases in this category to present like this: |
+ // OnLoginSuccess(..., ..., true) -> OnLoginFailure(). |
+ ChromeThread::PostTask( |
+ ChromeThread::UI, FROM_HERE, |
+ NewRunnableMethod(this, &ParallelAuthenticator::OnLoginSuccess, |
+ current_state_->credentials(), true)); |
+ } |
+ } |
+ ChromeThread::PostTask( |
+ ChromeThread::UI, FROM_HERE, |
+ NewRunnableMethod(this, &ParallelAuthenticator::OnLoginFailure, |
+ current_state_->online_outcome())); |
+ break; |
+ case HAVE_NEW_PW: |
+ key_migrator_ = |
+ CryptohomeOp::CreateMigrateAttempt(reauth_state_.get(), |
+ this, |
+ false, |
+ reauth_state_->ascii_hash); |
+ ChromeThread::PostTask( |
+ ChromeThread::UI, FROM_HERE, |
+ NewRunnableMethod(key_migrator_.get(), &CryptohomeOp::Initiate)); |
+ break; |
+ case OFFLINE_LOGIN: |
+ request_pending = !current_state_->online_complete(); |
+ // Fall through. |
+ case UNLOCK: |
+ // Fall through. |
+ case ONLINE_LOGIN: |
+ ChromeThread::PostTask( |
+ ChromeThread::UI, FROM_HERE, |
+ NewRunnableMethod(this, &ParallelAuthenticator::OnLoginSuccess, |
+ current_state_->credentials(), request_pending)); |
+ break; |
+ case LOCAL_LOGIN: |
+ ChromeThread::PostTask( |
+ ChromeThread::UI, FROM_HERE, |
+ NewRunnableMethod( |
+ this, |
+ &ParallelAuthenticator::OnOffTheRecordLoginSuccess)); |
+ break; |
+ case LOGIN_FAILED: |
+ current_state_->ResetCryptohomeStatus(); |
+ ChromeThread::PostTask( |
+ ChromeThread::FILE, FROM_HERE, |
+ NewRunnableMethod(this, &ParallelAuthenticator::CheckLocalaccount, |
+ current_state_->online_outcome())); |
+ break; |
+ default: |
+ NOTREACHED(); |
+ break; |
+ } |
+} |
+ |
+ParallelAuthenticator::AuthState ParallelAuthenticator::ResolveState() { |
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); |
+ // If we haven't mounted the user's home dir yet, we can't be done. |
+ // We never get past here if a cryptohome op is still pending. |
+ // This is an important invariant. |
+ if (!current_state_->cryptohome_complete()) |
+ return CONTINUE; |
+ |
+ AuthState state = (reauth_state_.get() ? ResolveReauthState() : CONTINUE); |
+ if (state != CONTINUE) |
+ return state; |
+ |
+ if (current_state_->cryptohome_outcome()) |
+ state = ResolveCryptohomeSuccessState(); |
+ else |
+ state = ResolveCryptohomeFailureState(); |
+ |
+ DCHECK(current_state_->cryptohome_complete()); // Ensure invariant holds. |
+ key_migrator_ = NULL; |
+ data_remover_ = NULL; |
+ guest_mounter_ = NULL; |
+ key_checker_ = NULL; |
+ |
+ if (state != POSSIBLE_PW_CHANGE && |
+ state != NO_MOUNT && |
+ state != OFFLINE_LOGIN) |
+ return state; |
+ |
+ if (current_state_->online_complete()) { |
+ if (current_state_->online_outcome().reason() == LoginFailure::NONE) { |
+ // Online attempt succeeded as well, so combine the results. |
+ return ResolveOnlineSuccessState(state); |
+ } else { |
+ // Online login attempt was rejected or failed to occur. |
+ return ResolveOnlineFailureState(state); |
+ } |
+ } |
+ // if online isn't complete yet, just return the offline result. |
+ return state; |
+} |
+ |
+ParallelAuthenticator::AuthState |
+ParallelAuthenticator::ResolveReauthState() { |
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); |
+ if (reauth_state_->cryptohome_complete()) { |
+ if (!reauth_state_->cryptohome_outcome()) { |
+ // If we've tried to migrate and failed, log the error and just wait |
+ // til next time the user logs in to migrate their cryptohome key. |
+ LOG(ERROR) << "Failed to migrate cryptohome key: " |
+ << reauth_state_->cryptohome_code(); |
+ } |
+ reauth_state_.reset(NULL); |
+ return ONLINE_LOGIN; |
+ } |
+ // Haven't tried the migrate yet, must be processing the online auth attempt. |
+ if (!reauth_state_->online_complete()) { |
+ NOTREACHED(); // Shouldn't be here at all, if online reauth isn't done! |
+ return CONTINUE; |
+ } |
+ if (reauth_state_->online_outcome().reason() == LoginFailure::NONE) |
+ return HAVE_NEW_PW; |
+ else |
+ return NEED_NEW_PW; |
+} |
+ |
+ParallelAuthenticator::AuthState |
+ParallelAuthenticator::ResolveCryptohomeFailureState() { |
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); |
+ if (data_remover_.get()) { |
+ return FAILED_REMOVE; |
+ } else if (guest_mounter_.get()) { |
+ return FAILED_TMPFS; |
+ } else if (key_migrator_.get()) { |
+ return NEED_OLD_PW; |
+ } else if (key_checker_.get()) { |
+ return LOGIN_FAILED; |
+ } else if (current_state_->cryptohome_code() == |
+ chromeos::kCryptohomeMountErrorKeyFailure) { |
+ // If we tried a mount but they used the wrong key, we may need to |
+ // ask the user for her old password. We'll only know once we've |
+ // done the online check. |
+ return POSSIBLE_PW_CHANGE; |
+ } else if (current_state_->cryptohome_code() == |
+ chromeos::kCryptohomeMountErrorUserDoesNotExist) { |
+ // If we tried a mount but the user did not exist, then we should wait |
+ // for online login to succeed and try again with the "create" flag set. |
+ return NO_MOUNT; |
+ } else { |
+ return FAILED_MOUNT; |
+ } |
+} |
+ |
+ParallelAuthenticator::AuthState |
+ParallelAuthenticator::ResolveCryptohomeSuccessState() { |
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); |
+ if (data_remover_.get()) { |
+ return CREATE_NEW; |
+ } else if (guest_mounter_.get()) { |
+ return LOCAL_LOGIN; |
+ } else if (key_migrator_.get()) { |
+ return RECOVER_MOUNT; |
+ } else if (key_checker_.get()) { |
+ return UNLOCK; |
+ } else { |
+ return OFFLINE_LOGIN; |
+ } |
+} |
+ |
+ParallelAuthenticator::AuthState |
+ParallelAuthenticator::ResolveOnlineFailureState( |
+ ParallelAuthenticator::AuthState offline_state) { |
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); |
+ if (offline_state == OFFLINE_LOGIN) { |
+ if (current_state_->online_outcome().error().state() == |
+ GoogleServiceAuthError::CONNECTION_FAILED) { |
+ // Couldn't do an online check, so just go with the offline result. |
+ return OFFLINE_LOGIN; |
+ } |
+ // Otherwise, online login was rejected! |
+ if (current_state_->online_outcome().error().state() == |
+ GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS) { |
+ return NEED_NEW_PW; |
+ } else { |
+ return ONLINE_FAILED; |
+ } |
+ } |
+ return LOGIN_FAILED; |
+} |
+ |
+ParallelAuthenticator::AuthState |
+ParallelAuthenticator::ResolveOnlineSuccessState( |
+ ParallelAuthenticator::AuthState offline_state) { |
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); |
+ switch (offline_state) { |
+ case POSSIBLE_PW_CHANGE: |
+ return NEED_OLD_PW; |
+ case NO_MOUNT: |
+ return CREATE_NEW; |
+ case OFFLINE_LOGIN: |
+ return ONLINE_LOGIN; |
+ default: |
+ NOTREACHED(); |
+ return offline_state; |
+ } |
+} |
+ |
+void ParallelAuthenticator::LoadSystemSalt() { |
+ if (!system_salt_.empty()) |
+ return; |
+ system_salt_ = CrosLibrary::Get()->GetCryptohomeLibrary()->GetSystemSalt(); |
+ CHECK(!system_salt_.empty()); |
+ CHECK_EQ(system_salt_.size() % 2, 0U); |
+} |
+ |
+void ParallelAuthenticator::LoadLocalaccount(const std::string& filename) { |
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); |
+ { |
+ AutoLock for_this_block(localaccount_lock_); |
+ if (checked_for_localaccount_) |
+ return; |
+ } |
+ FilePath localaccount_file; |
+ std::string localaccount; |
+ if (PathService::Get(base::DIR_EXE, &localaccount_file)) { |
+ localaccount_file = localaccount_file.Append(filename); |
+ LOG(INFO) << "looking for localaccount in " << localaccount_file.value(); |
+ |
+ ReadFileToString(localaccount_file, &localaccount); |
+ TrimWhitespaceASCII(localaccount, TRIM_TRAILING, &localaccount); |
+ LOG(INFO) << "Loading localaccount: " << localaccount; |
+ } else { |
+ LOG(INFO) << "Assuming no localaccount"; |
+ } |
+ SetLocalaccount(localaccount); |
+} |
+ |
+void ParallelAuthenticator::SetLocalaccount(const std::string& new_name) { |
+ localaccount_ = new_name; |
+ { // extra braces for clarity about AutoLock scope. |
+ AutoLock for_this_block(localaccount_lock_); |
+ checked_for_localaccount_ = true; |
+ } |
+} |
+ |
+ |
+std::string ParallelAuthenticator::HashPassword(const std::string& password) { |
+ // Get salt, ascii encode, update sha with that, then update with ascii |
+ // of password, then end. |
+ std::string ascii_salt = SaltAsAscii(); |
+ unsigned char passhash_buf[kPassHashLen]; |
+ char ascii_buf[kPassHashLen + 1]; |
+ |
+ // Hash salt and password |
+ SHA256Context ctx; |
+ SHA256_Begin(&ctx); |
+ SHA256_Update(&ctx, |
+ reinterpret_cast<const unsigned char*>(ascii_salt.data()), |
+ static_cast<unsigned int>(ascii_salt.length())); |
+ SHA256_Update(&ctx, |
+ reinterpret_cast<const unsigned char*>(password.data()), |
+ static_cast<unsigned int>(password.length())); |
+ SHA256_End(&ctx, |
+ passhash_buf, |
+ NULL, |
+ static_cast<unsigned int>(sizeof(passhash_buf))); |
+ |
+ std::vector<unsigned char> passhash(passhash_buf, |
+ passhash_buf + sizeof(passhash_buf)); |
+ BinaryToHex(passhash, |
+ passhash.size() / 2, // only want top half, at least for now. |
+ ascii_buf, |
+ sizeof(ascii_buf)); |
+ return std::string(ascii_buf, sizeof(ascii_buf) - 1); |
+} |
+ |
+std::string ParallelAuthenticator::SaltAsAscii() { |
+ LoadSystemSalt(); // no-op if it's already loaded. |
+ unsigned int salt_len = system_salt_.size(); |
+ char ascii_salt[2 * salt_len + 1]; |
+ if (ParallelAuthenticator::BinaryToHex(system_salt_, |
+ salt_len, |
+ ascii_salt, |
+ sizeof(ascii_salt))) { |
+ return std::string(ascii_salt, sizeof(ascii_salt) - 1); |
+ } else { |
+ return std::string(); |
+ } |
+} |
+ |
+// static |
+bool ParallelAuthenticator::BinaryToHex( |
+ const std::vector<unsigned char>& binary, |
+ const unsigned int binary_len, |
+ char* hex_string, |
+ const unsigned int len) { |
+ if (len < 2*binary_len) |
+ return false; |
+ memset(hex_string, 0, len); |
+ for (uint i = 0, j = 0; i < binary_len; i++, j+=2) |
+ snprintf(hex_string + j, len - j, "%02x", binary[i]); |
+ return true; |
+} |
+ |
+} // namespace chromeos |