//
// Copyright (C) 2015 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include "tpm_manager/server/tpm_manager_service.h"
#include <base/callback.h>
#include <base/command_line.h>
#include <brillo/bind_lambda.h>
namespace tpm_manager {
TpmManagerService::TpmManagerService(bool wait_for_ownership,
LocalDataStore* local_data_store,
TpmStatus* tpm_status,
TpmInitializer* tpm_initializer,
TpmNvram* tpm_nvram)
: local_data_store_(local_data_store),
tpm_status_(tpm_status),
tpm_initializer_(tpm_initializer),
tpm_nvram_(tpm_nvram),
wait_for_ownership_(wait_for_ownership),
weak_factory_(this) {}
bool TpmManagerService::Initialize() {
LOG(INFO) << "TpmManager service started.";
worker_thread_.reset(new base::Thread("TpmManager Service Worker"));
worker_thread_->StartWithOptions(
base::Thread::Options(base::MessageLoop::TYPE_IO, 0));
base::Closure task = base::Bind(&TpmManagerService::InitializeTask,
base::Unretained(this));
worker_thread_->task_runner()->PostNonNestableTask(FROM_HERE, task);
return true;
}
void TpmManagerService::InitializeTask() {
if (!tpm_status_->IsTpmEnabled()) {
LOG(WARNING) << __func__ << ": TPM is disabled.";
return;
}
if (!wait_for_ownership_) {
VLOG(1) << "Initializing TPM.";
if (!tpm_initializer_->InitializeTpm()) {
LOG(WARNING) << __func__ << ": TPM initialization failed.";
return;
}
}
}
void TpmManagerService::GetTpmStatus(const GetTpmStatusRequest& request,
const GetTpmStatusCallback& callback) {
PostTaskToWorkerThread<GetTpmStatusReply>(
request, callback, &TpmManagerService::GetTpmStatusTask);
}
void TpmManagerService::GetTpmStatusTask(
const GetTpmStatusRequest& request,
const std::shared_ptr<GetTpmStatusReply>& result) {
VLOG(1) << __func__;
result->set_enabled(tpm_status_->IsTpmEnabled());
result->set_owned(tpm_status_->IsTpmOwned());
LocalData local_data;
if (local_data_store_ && local_data_store_->Read(&local_data)) {
*result->mutable_local_data() = local_data;
}
int counter;
int threshold;
bool lockout;
int lockout_time_remaining;
if (tpm_status_->GetDictionaryAttackInfo(&counter, &threshold, &lockout,
&lockout_time_remaining)) {
result->set_dictionary_attack_counter(counter);
result->set_dictionary_attack_threshold(threshold);
result->set_dictionary_attack_lockout_in_effect(lockout);
result->set_dictionary_attack_lockout_seconds_remaining(
lockout_time_remaining);
}
result->set_status(STATUS_SUCCESS);
}
void TpmManagerService::TakeOwnership(const TakeOwnershipRequest& request,
const TakeOwnershipCallback& callback) {
PostTaskToWorkerThread<TakeOwnershipReply>(
request, callback, &TpmManagerService::TakeOwnershipTask);
}
void TpmManagerService::TakeOwnershipTask(
const TakeOwnershipRequest& request,
const std::shared_ptr<TakeOwnershipReply>& result) {
VLOG(1) << __func__;
if (!tpm_status_->IsTpmEnabled()) {
result->set_status(STATUS_NOT_AVAILABLE);
return;
}
if (!tpm_initializer_->InitializeTpm()) {
result->set_status(STATUS_UNEXPECTED_DEVICE_ERROR);
return;
}
result->set_status(STATUS_SUCCESS);
}
void TpmManagerService::RemoveOwnerDependency(
const RemoveOwnerDependencyRequest& request,
const RemoveOwnerDependencyCallback& callback) {
PostTaskToWorkerThread<RemoveOwnerDependencyReply>(
request, callback, &TpmManagerService::RemoveOwnerDependencyTask);
}
void TpmManagerService::RemoveOwnerDependencyTask(
const RemoveOwnerDependencyRequest& request,
const std::shared_ptr<RemoveOwnerDependencyReply>& result) {
VLOG(1) << __func__;
LocalData local_data;
if (!local_data_store_->Read(&local_data)) {
result->set_status(STATUS_UNEXPECTED_DEVICE_ERROR);
return;
}
RemoveOwnerDependency(request.owner_dependency(), &local_data);
if (!local_data_store_->Write(local_data)) {
result->set_status(STATUS_UNEXPECTED_DEVICE_ERROR);
return;
}
result->set_status(STATUS_SUCCESS);
}
void TpmManagerService::RemoveOwnerDependency(
const std::string& owner_dependency, LocalData* local_data) {
google::protobuf::RepeatedPtrField<std::string>* dependencies =
local_data->mutable_owner_dependency();
for (int i = 0; i < dependencies->size(); i++) {
if (dependencies->Get(i) == owner_dependency) {
dependencies->SwapElements(i, (dependencies->size() - 1));
dependencies->RemoveLast();
break;
}
}
if (dependencies->empty()) {
local_data->clear_owner_password();
local_data->clear_endorsement_password();
local_data->clear_lockout_password();
}
}
void TpmManagerService::DefineNvram(const DefineNvramRequest& request,
const DefineNvramCallback& callback) {
PostTaskToWorkerThread<DefineNvramReply>(
request, callback, &TpmManagerService::DefineNvramTask);
}
void TpmManagerService::DefineNvramTask(
const DefineNvramRequest& request,
const std::shared_ptr<DefineNvramReply>& result) {
VLOG(1) << __func__;
if (!tpm_nvram_->DefineNvram(request.index(), request.length())) {
result->set_status(STATUS_UNEXPECTED_DEVICE_ERROR);
return;
}
result->set_status(STATUS_SUCCESS);
}
void TpmManagerService::DestroyNvram(const DestroyNvramRequest& request,
const DestroyNvramCallback& callback) {
PostTaskToWorkerThread<DestroyNvramReply>(
request, callback, &TpmManagerService::DestroyNvramTask);
}
void TpmManagerService::DestroyNvramTask(
const DestroyNvramRequest& request,
const std::shared_ptr<DestroyNvramReply>& result) {
VLOG(1) << __func__;
if (!tpm_nvram_->DestroyNvram(request.index())) {
result->set_status(STATUS_UNEXPECTED_DEVICE_ERROR);
return;
}
result->set_status(STATUS_SUCCESS);
}
void TpmManagerService::WriteNvram(const WriteNvramRequest& request,
const WriteNvramCallback& callback) {
PostTaskToWorkerThread<WriteNvramReply>(
request, callback, &TpmManagerService::WriteNvramTask);
}
void TpmManagerService::WriteNvramTask(
const WriteNvramRequest& request,
const std::shared_ptr<WriteNvramReply>& result) {
VLOG(1) << __func__;
if (!tpm_nvram_->WriteNvram(request.index(), request.data())) {
result->set_status(STATUS_UNEXPECTED_DEVICE_ERROR);
return;
}
result->set_status(STATUS_SUCCESS);
}
void TpmManagerService::ReadNvram(const ReadNvramRequest& request,
const ReadNvramCallback& callback) {
PostTaskToWorkerThread<ReadNvramReply>(
request, callback, &TpmManagerService::ReadNvramTask);
}
void TpmManagerService::ReadNvramTask(
const ReadNvramRequest& request,
const std::shared_ptr<ReadNvramReply>& result) {
VLOG(1) << __func__;
if (!tpm_nvram_->ReadNvram(request.index(), result->mutable_data())) {
result->set_status(STATUS_UNEXPECTED_DEVICE_ERROR);
return;
}
result->set_status(STATUS_SUCCESS);
}
void TpmManagerService::IsNvramDefined(const IsNvramDefinedRequest& request,
const IsNvramDefinedCallback& callback) {
PostTaskToWorkerThread<IsNvramDefinedReply>(
request, callback, &TpmManagerService::IsNvramDefinedTask);
}
void TpmManagerService::IsNvramDefinedTask(
const IsNvramDefinedRequest& request,
const std::shared_ptr<IsNvramDefinedReply>& result) {
VLOG(1) << __func__;
bool defined;
if (!tpm_nvram_->IsNvramDefined(request.index(), &defined)) {
result->set_status(STATUS_UNEXPECTED_DEVICE_ERROR);
return;
}
result->set_is_defined(defined);
result->set_status(STATUS_SUCCESS);
}
void TpmManagerService::IsNvramLocked(const IsNvramLockedRequest& request,
const IsNvramLockedCallback& callback) {
PostTaskToWorkerThread<IsNvramLockedReply>(
request, callback, &TpmManagerService::IsNvramLockedTask);
}
void TpmManagerService::IsNvramLockedTask(
const IsNvramLockedRequest& request,
const std::shared_ptr<IsNvramLockedReply>& result) {
VLOG(1) << __func__;
bool locked;
if (!tpm_nvram_->IsNvramLocked(request.index(), &locked)) {
result->set_status(STATUS_UNEXPECTED_DEVICE_ERROR);
return;
}
result->set_is_locked(locked);
result->set_status(STATUS_SUCCESS);
}
void TpmManagerService::GetNvramSize(const GetNvramSizeRequest& request,
const GetNvramSizeCallback& callback) {
PostTaskToWorkerThread<GetNvramSizeReply>(
request, callback, &TpmManagerService::GetNvramSizeTask);
}
void TpmManagerService::GetNvramSizeTask(
const GetNvramSizeRequest& request,
const std::shared_ptr<GetNvramSizeReply>& result) {
VLOG(1) << __func__;
size_t size;
if (!tpm_nvram_->GetNvramSize(request.index(), &size)) {
result->set_status(STATUS_UNEXPECTED_DEVICE_ERROR);
return;
}
result->set_size(size);
result->set_status(STATUS_SUCCESS);
}
template<typename ReplyProtobufType>
void TpmManagerService::TaskRelayCallback(
const base::Callback<void(const ReplyProtobufType&)> callback,
const std::shared_ptr<ReplyProtobufType>& reply) {
callback.Run(*reply);
}
template<typename ReplyProtobufType,
typename RequestProtobufType,
typename ReplyCallbackType,
typename TaskType>
void TpmManagerService::PostTaskToWorkerThread(RequestProtobufType& request,
ReplyCallbackType& callback,
TaskType task) {
auto result = std::make_shared<ReplyProtobufType>();
base::Closure background_task = base::Bind(task,
base::Unretained(this),
request,
result);
base::Closure reply = base::Bind(
&TpmManagerService::TaskRelayCallback<ReplyProtobufType>,
weak_factory_.GetWeakPtr(),
callback,
result);
worker_thread_->task_runner()->PostTaskAndReply(FROM_HERE,
background_task,
reply);
}
} // namespace tpm_manager