blob: 16170eb4f6b15fce4e55a4ae1db49a7efce8330e [file] [log] [blame]
// Copyright (c) 2012 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 "chromeos/cryptohome/async_method_caller.h"
#include "base/bind.h"
#include "base/containers/hash_tables.h"
#include "base/location.h"
#include "base/macros.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "chromeos/cryptohome/cryptohome_parameters.h"
#include "chromeos/dbus/dbus_thread_manager.h"
using chromeos::DBusThreadManager;
namespace cryptohome {
namespace {
AsyncMethodCaller* g_async_method_caller = NULL;
// The implementation of AsyncMethodCaller
class AsyncMethodCallerImpl : public AsyncMethodCaller {
public:
AsyncMethodCallerImpl() : weak_ptr_factory_(this) {
DBusThreadManager::Get()->GetCryptohomeClient()->SetAsyncCallStatusHandlers(
base::Bind(&AsyncMethodCallerImpl::HandleAsyncResponse,
weak_ptr_factory_.GetWeakPtr()),
base::Bind(&AsyncMethodCallerImpl::HandleAsyncDataResponse,
weak_ptr_factory_.GetWeakPtr()));
}
~AsyncMethodCallerImpl() override {
DBusThreadManager::Get()->GetCryptohomeClient()->
ResetAsyncCallStatusHandlers();
}
void AsyncCheckKey(const Identification& cryptohome_id,
const std::string& passhash,
Callback callback) override {
DBusThreadManager::Get()->GetCryptohomeClient()->AsyncCheckKey(
cryptohome_id, passhash,
base::Bind(&AsyncMethodCallerImpl::RegisterAsyncCallback,
weak_ptr_factory_.GetWeakPtr(), callback,
"Couldn't initiate async check of user's key."));
}
void AsyncMigrateKey(const Identification& cryptohome_id,
const std::string& old_hash,
const std::string& new_hash,
Callback callback) override {
DBusThreadManager::Get()->GetCryptohomeClient()->AsyncMigrateKey(
cryptohome_id, old_hash, new_hash,
base::Bind(&AsyncMethodCallerImpl::RegisterAsyncCallback,
weak_ptr_factory_.GetWeakPtr(), callback,
"Couldn't initiate aync migration of user's key"));
}
void AsyncMount(const Identification& cryptohome_id,
const std::string& passhash,
int flags,
Callback callback) override {
DBusThreadManager::Get()->GetCryptohomeClient()->AsyncMount(
cryptohome_id, passhash, flags,
base::Bind(&AsyncMethodCallerImpl::RegisterAsyncCallback,
weak_ptr_factory_.GetWeakPtr(), callback,
"Couldn't initiate async mount of cryptohome."));
}
void AsyncAddKey(const Identification& cryptohome_id,
const std::string& passhash,
const std::string& new_passhash,
Callback callback) override {
DBusThreadManager::Get()->GetCryptohomeClient()->AsyncAddKey(
cryptohome_id, passhash, new_passhash,
base::Bind(&AsyncMethodCallerImpl::RegisterAsyncCallback,
weak_ptr_factory_.GetWeakPtr(), callback,
"Couldn't initiate async key addition."));
}
void AsyncMountGuest(Callback callback) override {
DBusThreadManager::Get()->GetCryptohomeClient()->
AsyncMountGuest(base::Bind(
&AsyncMethodCallerImpl::RegisterAsyncCallback,
weak_ptr_factory_.GetWeakPtr(),
callback,
"Couldn't initiate async mount of cryptohome."));
}
void AsyncMountPublic(const Identification& public_mount_id,
int flags,
Callback callback) override {
DBusThreadManager::Get()->GetCryptohomeClient()->AsyncMountPublic(
public_mount_id, flags,
base::Bind(&AsyncMethodCallerImpl::RegisterAsyncCallback,
weak_ptr_factory_.GetWeakPtr(), callback,
"Couldn't initiate async mount public of cryptohome."));
}
void AsyncRemove(const Identification& cryptohome_id,
Callback callback) override {
DBusThreadManager::Get()->GetCryptohomeClient()->AsyncRemove(
cryptohome_id,
base::Bind(&AsyncMethodCallerImpl::RegisterAsyncCallback,
weak_ptr_factory_.GetWeakPtr(), callback,
"Couldn't initiate async removal of cryptohome."));
}
void AsyncTpmAttestationCreateEnrollRequest(
chromeos::attestation::PrivacyCAType pca_type,
const DataCallback& callback) override {
DBusThreadManager::Get()->GetCryptohomeClient()->
AsyncTpmAttestationCreateEnrollRequest(pca_type, base::Bind(
&AsyncMethodCallerImpl::RegisterAsyncDataCallback,
weak_ptr_factory_.GetWeakPtr(),
callback,
"Couldn't initiate async attestation enroll request."));
}
void AsyncTpmAttestationEnroll(chromeos::attestation::PrivacyCAType pca_type,
const std::string& pca_response,
const Callback& callback) override {
DBusThreadManager::Get()->GetCryptohomeClient()->
AsyncTpmAttestationEnroll(pca_type, pca_response, base::Bind(
&AsyncMethodCallerImpl::RegisterAsyncCallback,
weak_ptr_factory_.GetWeakPtr(),
callback,
"Couldn't initiate async attestation enroll."));
}
void AsyncTpmAttestationCreateCertRequest(
chromeos::attestation::PrivacyCAType pca_type,
chromeos::attestation::AttestationCertificateProfile certificate_profile,
const Identification& cryptohome_id,
const std::string& request_origin,
const DataCallback& callback) override {
DBusThreadManager::Get()
->GetCryptohomeClient()
->AsyncTpmAttestationCreateCertRequest(
pca_type, certificate_profile, cryptohome_id, request_origin,
base::Bind(&AsyncMethodCallerImpl::RegisterAsyncDataCallback,
weak_ptr_factory_.GetWeakPtr(), callback,
"Couldn't initiate async attestation cert request."));
}
void AsyncTpmAttestationFinishCertRequest(
const std::string& pca_response,
chromeos::attestation::AttestationKeyType key_type,
const Identification& cryptohome_id,
const std::string& key_name,
const DataCallback& callback) override {
DBusThreadManager::Get()
->GetCryptohomeClient()
->AsyncTpmAttestationFinishCertRequest(
pca_response, key_type, cryptohome_id, key_name,
base::Bind(
&AsyncMethodCallerImpl::RegisterAsyncDataCallback,
weak_ptr_factory_.GetWeakPtr(), callback,
"Couldn't initiate async attestation finish cert request."));
}
void TpmAttestationRegisterKey(
chromeos::attestation::AttestationKeyType key_type,
const Identification& cryptohome_id,
const std::string& key_name,
const Callback& callback) override {
DBusThreadManager::Get()->GetCryptohomeClient()->TpmAttestationRegisterKey(
key_type, cryptohome_id, key_name,
base::Bind(&AsyncMethodCallerImpl::RegisterAsyncCallback,
weak_ptr_factory_.GetWeakPtr(), callback,
"Couldn't initiate async attestation register key."));
}
void TpmAttestationSignEnterpriseChallenge(
chromeos::attestation::AttestationKeyType key_type,
const Identification& cryptohome_id,
const std::string& key_name,
const std::string& domain,
const std::string& device_id,
chromeos::attestation::AttestationChallengeOptions options,
const std::string& challenge,
const DataCallback& callback) override {
DBusThreadManager::Get()
->GetCryptohomeClient()
->TpmAttestationSignEnterpriseChallenge(
key_type, cryptohome_id, key_name, domain, device_id, options,
challenge,
base::Bind(
&AsyncMethodCallerImpl::RegisterAsyncDataCallback,
weak_ptr_factory_.GetWeakPtr(), callback,
"Couldn't initiate async attestation enterprise challenge."));
}
void TpmAttestationSignSimpleChallenge(
chromeos::attestation::AttestationKeyType key_type,
const Identification& cryptohome_id,
const std::string& key_name,
const std::string& challenge,
const DataCallback& callback) override {
DBusThreadManager::Get()
->GetCryptohomeClient()
->TpmAttestationSignSimpleChallenge(
key_type, cryptohome_id, key_name, challenge,
base::Bind(
&AsyncMethodCallerImpl::RegisterAsyncDataCallback,
weak_ptr_factory_.GetWeakPtr(), callback,
"Couldn't initiate async attestation simple challenge."));
}
void AsyncGetSanitizedUsername(const Identification& cryptohome_id,
const DataCallback& callback) override {
DBusThreadManager::Get()->GetCryptohomeClient()->GetSanitizedUsername(
cryptohome_id,
base::Bind(&AsyncMethodCallerImpl::GetSanitizedUsernameCallback,
weak_ptr_factory_.GetWeakPtr(), callback));
}
virtual void GetSanitizedUsernameCallback(
const DataCallback& callback,
const chromeos::DBusMethodCallStatus call_status,
const std::string& result) {
callback.Run(true, result);
}
private:
struct CallbackElement {
CallbackElement() {}
explicit CallbackElement(const AsyncMethodCaller::Callback& callback)
: callback(callback),
task_runner(base::ThreadTaskRunnerHandle::Get()) {}
AsyncMethodCaller::Callback callback;
scoped_refptr<base::SingleThreadTaskRunner> task_runner;
};
struct DataCallbackElement {
DataCallbackElement() {}
explicit DataCallbackElement(
const AsyncMethodCaller::DataCallback& callback)
: data_callback(callback),
task_runner(base::ThreadTaskRunnerHandle::Get()) {}
AsyncMethodCaller::DataCallback data_callback;
scoped_refptr<base::SingleThreadTaskRunner> task_runner;
};
typedef base::hash_map<int, CallbackElement> CallbackMap;
typedef base::hash_map<int, DataCallbackElement> DataCallbackMap;
// Handles the response for async calls.
// Below is described how async calls work.
// 1. CryptohomeClient::AsyncXXX returns "async ID".
// 2. RegisterAsyncCallback registers the "async ID" with the user-provided
// callback.
// 3. Cryptohome will return the result asynchronously as a signal with
// "async ID"
// 4. "HandleAsyncResponse" handles the result signal and call the registered
// callback associated with the "async ID".
void HandleAsyncResponse(int async_id, bool return_status, int return_code) {
const CallbackMap::iterator it = callback_map_.find(async_id);
if (it == callback_map_.end()) {
LOG(ERROR) << "Received signal for unknown async_id " << async_id;
return;
}
it->second.task_runner->PostTask(
FROM_HERE, base::Bind(it->second.callback, return_status,
static_cast<MountError>(return_code)));
callback_map_.erase(it);
}
// Similar to HandleAsyncResponse but for signals with a raw data payload.
void HandleAsyncDataResponse(int async_id,
bool return_status,
const std::string& return_data) {
const DataCallbackMap::iterator it = data_callback_map_.find(async_id);
if (it == data_callback_map_.end()) {
LOG(ERROR) << "Received signal for unknown async_id " << async_id;
return;
}
it->second.task_runner->PostTask(
FROM_HERE,
base::Bind(it->second.data_callback, return_status, return_data));
data_callback_map_.erase(it);
}
// Registers a callback which is called when the result for AsyncXXX is ready.
void RegisterAsyncCallback(
Callback callback, const char* error, int async_id) {
if (async_id == chromeos::CryptohomeClient::kNotReadyAsyncId) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::Bind(callback,
false, // return status
cryptohome::MOUNT_ERROR_FATAL));
return;
}
if (async_id == 0) {
LOG(ERROR) << error;
return;
}
VLOG(1) << "Adding handler for " << async_id;
DCHECK_EQ(callback_map_.count(async_id), 0U);
DCHECK_EQ(data_callback_map_.count(async_id), 0U);
callback_map_[async_id] = CallbackElement(callback);
}
// Registers a callback which is called when the result for AsyncXXX is ready.
void RegisterAsyncDataCallback(
DataCallback callback, const char* error, int async_id) {
if (async_id == chromeos::CryptohomeClient::kNotReadyAsyncId) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::Bind(callback,
false, // return status
std::string()));
return;
}
if (async_id == 0) {
LOG(ERROR) << error;
return;
}
VLOG(1) << "Adding handler for " << async_id;
DCHECK_EQ(callback_map_.count(async_id), 0U);
DCHECK_EQ(data_callback_map_.count(async_id), 0U);
data_callback_map_[async_id] = DataCallbackElement(callback);
}
CallbackMap callback_map_;
DataCallbackMap data_callback_map_;
base::WeakPtrFactory<AsyncMethodCallerImpl> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(AsyncMethodCallerImpl);
};
} // namespace
// static
void AsyncMethodCaller::Initialize() {
if (g_async_method_caller) {
LOG(WARNING) << "AsyncMethodCaller was already initialized";
return;
}
g_async_method_caller = new AsyncMethodCallerImpl();
VLOG(1) << "AsyncMethodCaller initialized";
}
// static
void AsyncMethodCaller::InitializeForTesting(
AsyncMethodCaller* async_method_caller) {
if (g_async_method_caller) {
LOG(WARNING) << "AsyncMethodCaller was already initialized";
return;
}
g_async_method_caller = async_method_caller;
VLOG(1) << "AsyncMethodCaller initialized";
}
// static
void AsyncMethodCaller::Shutdown() {
if (!g_async_method_caller) {
LOG(WARNING) << "AsyncMethodCaller::Shutdown() called with NULL manager";
return;
}
delete g_async_method_caller;
g_async_method_caller = NULL;
VLOG(1) << "AsyncMethodCaller Shutdown completed";
}
// static
AsyncMethodCaller* AsyncMethodCaller::GetInstance() {
return g_async_method_caller;
}
} // namespace cryptohome