| // |
| // 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 <stdio.h> |
| #include <stdlib.h> |
| #include <sysexits.h> |
| |
| #include <memory> |
| #include <string> |
| |
| #include <base/command_line.h> |
| #include <base/logging.h> |
| #include <base/message_loop/message_loop.h> |
| #include <brillo/bind_lambda.h> |
| #include <brillo/daemons/daemon.h> |
| #include <brillo/syslog_logging.h> |
| |
| #include "tpm_manager/client/tpm_nvram_dbus_proxy.h" |
| #include "tpm_manager/client/tpm_ownership_dbus_proxy.h" |
| #include "tpm_manager/common/print_tpm_ownership_interface_proto.h" |
| #include "tpm_manager/common/print_tpm_nvram_interface_proto.h" |
| #include "tpm_manager/common/tpm_ownership_interface.pb.h" |
| #include "tpm_manager/common/tpm_nvram_interface.pb.h" |
| |
| namespace tpm_manager { |
| |
| const char kGetTpmStatusCommand[] = "status"; |
| const char kTakeOwnershipCommand[] = "take_ownership"; |
| const char kRemoveOwnerDependencyCommand[] = "remove_dependency"; |
| const char kDefineNvramCommand[] = "define_nvram"; |
| const char kDestroyNvramCommand[] = "destroy_nvram"; |
| const char kWriteNvramCommand[] = "write_nvram"; |
| const char kReadNvramCommand[] = "read_nvram"; |
| const char kIsNvramDefinedCommand[] = "is_nvram_defined"; |
| const char kIsNvramLockedCommand[] = "is_nvram_locked"; |
| const char kGetNvramSizeCommand[] = "get_nvram_size"; |
| |
| const char kNvramIndexArg[] = "nvram_index"; |
| const char kNvramLengthArg[] = "nvram_length"; |
| const char kNvramDataArg[] = "nvram_data"; |
| |
| const char kUsage[] = R"( |
| Usage: tpm_manager_client <command> [<arguments>] |
| Commands (used as switches): |
| --status |
| Prints the current status of the Tpm. |
| --take_ownership |
| Takes ownership of the Tpm with a random password. |
| --remove_dependency=<owner_dependency> |
| Removes the provided Tpm owner dependency. |
| --define_nvram |
| Defines an NV space at |nvram_index| with length |nvram_length|. |
| --destroy_nvram |
| Destroys the NV space at |nvram_index|. |
| --write_nvram |
| Writes the NV space at |nvram_index| with |nvram_data|. |
| --read_nvram |
| Prints the contents of the NV space at |nvram_index|. |
| --is_nvram_defined |
| Prints whether the NV space at |nvram_index| is defined. |
| --is_nvram_locked |
| Prints whether the NV space at |nvram_index| is locked for writing. |
| --get_nvram_size |
| Prints the size of the NV space at |nvram_index|. |
| Arguments (used as switches): |
| --nvram_index=<index> |
| Index of NV space to operate on. |
| --nvram_length=<length> |
| Size in bytes of the NV space to be created. |
| --nvram_data=<data> |
| Data to write to NV space. |
| )"; |
| |
| using ClientLoopBase = brillo::Daemon; |
| class ClientLoop : public ClientLoopBase { |
| public: |
| ClientLoop() = default; |
| ~ClientLoop() override = default; |
| |
| protected: |
| int OnInit() override { |
| int exit_code = ClientLoopBase::OnInit(); |
| if (exit_code != EX_OK) { |
| LOG(ERROR) << "Error initializing tpm_manager_client."; |
| return exit_code; |
| } |
| TpmNvramDBusProxy* nvram_proxy = new TpmNvramDBusProxy(); |
| if (!nvram_proxy->Initialize()) { |
| LOG(ERROR) << "Error initializing proxy to nvram interface."; |
| return EX_UNAVAILABLE; |
| } |
| TpmOwnershipDBusProxy* ownership_proxy = new TpmOwnershipDBusProxy(); |
| if (!ownership_proxy->Initialize()) { |
| LOG(ERROR) << "Error initializing proxy to ownership interface."; |
| return EX_UNAVAILABLE; |
| } |
| tpm_nvram_.reset(nvram_proxy); |
| tpm_ownership_.reset(ownership_proxy); |
| exit_code = ScheduleCommand(); |
| if (exit_code == EX_USAGE) { |
| printf("%s", kUsage); |
| } |
| return exit_code; |
| } |
| |
| void OnShutdown(int* exit_code) override { |
| tpm_nvram_.reset(); |
| tpm_ownership_.reset(); |
| ClientLoopBase::OnShutdown(exit_code); |
| } |
| |
| private: |
| // Posts tasks on to the message loop based on command line flags. |
| int ScheduleCommand() { |
| base::Closure task; |
| base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); |
| if (command_line->HasSwitch("help") || command_line->HasSwitch("h")) { |
| return EX_USAGE; |
| } else if (command_line->HasSwitch(kGetTpmStatusCommand)) { |
| task = base::Bind(&ClientLoop::HandleGetTpmStatus, |
| weak_factory_.GetWeakPtr()); |
| } else if (command_line->HasSwitch(kTakeOwnershipCommand)) { |
| task = base::Bind(&ClientLoop::HandleTakeOwnership, |
| weak_factory_.GetWeakPtr()); |
| } else if (command_line->HasSwitch(kRemoveOwnerDependencyCommand)) { |
| task = base::Bind( |
| &ClientLoop::HandleRemoveOwnerDependency, weak_factory_.GetWeakPtr(), |
| command_line->GetSwitchValueASCII(kRemoveOwnerDependencyCommand)); |
| } else if (command_line->HasSwitch(kDefineNvramCommand)) { |
| if (!command_line->HasSwitch(kNvramIndexArg) || |
| !command_line->HasSwitch(kNvramLengthArg)) { |
| LOG(ERROR) << "Cannot define nvram without a valid index and length."; |
| return EX_USAGE; |
| } |
| task = base::Bind( |
| &ClientLoop::HandleDefineNvram, weak_factory_.GetWeakPtr(), |
| atoi(command_line->GetSwitchValueASCII(kNvramIndexArg).c_str()), |
| atoi(command_line->GetSwitchValueASCII(kNvramLengthArg).c_str())); |
| } else if (command_line->HasSwitch(kDestroyNvramCommand)) { |
| if (!command_line->HasSwitch(kNvramIndexArg)) { |
| LOG(ERROR) << "Cannot destroy nvram without a valid index."; |
| return EX_USAGE; |
| } |
| task = base::Bind( |
| &ClientLoop::HandleDestroyNvram, weak_factory_.GetWeakPtr(), |
| atoi(command_line->GetSwitchValueASCII(kNvramIndexArg).c_str())); |
| } else if (command_line->HasSwitch(kWriteNvramCommand)) { |
| if (!command_line->HasSwitch(kNvramIndexArg) || |
| !command_line->HasSwitch(kNvramDataArg)) { |
| LOG(ERROR) << "Cannot write nvram without a valid index and data."; |
| return EX_USAGE; |
| } |
| task = base::Bind( |
| &ClientLoop::HandleWriteNvram, weak_factory_.GetWeakPtr(), |
| atoi(command_line->GetSwitchValueASCII(kNvramIndexArg).c_str()), |
| command_line->GetSwitchValueASCII(kNvramDataArg)); |
| } else if (command_line->HasSwitch(kReadNvramCommand)) { |
| if (!command_line->HasSwitch(kNvramIndexArg)) { |
| LOG(ERROR) << "Cannot read nvram without a valid index."; |
| return EX_USAGE; |
| } |
| task = base::Bind( |
| &ClientLoop::HandleReadNvram, weak_factory_.GetWeakPtr(), |
| atoi(command_line->GetSwitchValueASCII(kNvramIndexArg).c_str())); |
| } else if (command_line->HasSwitch(kIsNvramDefinedCommand)) { |
| if (!command_line->HasSwitch(kNvramIndexArg)) { |
| LOG(ERROR) << "Cannot query nvram without a valid index."; |
| return EX_USAGE; |
| } |
| task = base::Bind( |
| &ClientLoop::HandleIsNvramDefined, weak_factory_.GetWeakPtr(), |
| atoi(command_line->GetSwitchValueASCII(kNvramIndexArg).c_str())); |
| } else if (command_line->HasSwitch(kIsNvramLockedCommand)) { |
| if (!command_line->HasSwitch(kNvramIndexArg)) { |
| LOG(ERROR) << "Cannot query nvram without a valid index."; |
| return EX_USAGE; |
| } |
| task = base::Bind( |
| &ClientLoop::HandleIsNvramLocked, weak_factory_.GetWeakPtr(), |
| atoi(command_line->GetSwitchValueASCII(kNvramIndexArg).c_str())); |
| } else if (command_line->HasSwitch(kGetNvramSizeCommand)) { |
| if (!command_line->HasSwitch(kNvramIndexArg)) { |
| LOG(ERROR) << "Cannot query nvram without a valid index."; |
| return EX_USAGE; |
| } |
| task = base::Bind( |
| &ClientLoop::HandleGetNvramSize, weak_factory_.GetWeakPtr(), |
| atoi(command_line->GetSwitchValueASCII(kNvramIndexArg).c_str())); |
| } else { |
| // Command line arguments did not match any valid commands. |
| LOG(ERROR) << "No Valid Command selected."; |
| return EX_USAGE; |
| } |
| base::MessageLoop::current()->PostTask(FROM_HERE, task); |
| return EX_OK; |
| } |
| |
| // Template to print reply protobuf. |
| template <typename ProtobufType> |
| void PrintReplyAndQuit(const ProtobufType& reply) { |
| LOG(INFO) << "Message Reply: " << GetProtoDebugString(reply); |
| Quit(); |
| } |
| |
| void HandleGetTpmStatus() { |
| GetTpmStatusRequest request; |
| tpm_ownership_->GetTpmStatus( |
| request, base::Bind(&ClientLoop::PrintReplyAndQuit<GetTpmStatusReply>, |
| weak_factory_.GetWeakPtr())); |
| } |
| |
| void HandleTakeOwnership() { |
| TakeOwnershipRequest request; |
| tpm_ownership_->TakeOwnership( |
| request, base::Bind(&ClientLoop::PrintReplyAndQuit<TakeOwnershipReply>, |
| weak_factory_.GetWeakPtr())); |
| } |
| |
| void HandleRemoveOwnerDependency(const std::string& owner_dependency) { |
| RemoveOwnerDependencyRequest request; |
| request.set_owner_dependency(owner_dependency); |
| tpm_ownership_->RemoveOwnerDependency( |
| request, |
| base::Bind(&ClientLoop::PrintReplyAndQuit<RemoveOwnerDependencyReply>, |
| weak_factory_.GetWeakPtr())); |
| } |
| |
| void HandleDefineNvram(uint32_t index, size_t length) { |
| DefineNvramRequest request; |
| request.set_index(index); |
| request.set_length(length); |
| tpm_nvram_->DefineNvram( |
| request, base::Bind(&ClientLoop::PrintReplyAndQuit<DefineNvramReply>, |
| weak_factory_.GetWeakPtr())); |
| } |
| |
| void HandleDestroyNvram(uint32_t index) { |
| DestroyNvramRequest request; |
| request.set_index(index); |
| tpm_nvram_->DestroyNvram( |
| request, base::Bind(&ClientLoop::PrintReplyAndQuit<DestroyNvramReply>, |
| weak_factory_.GetWeakPtr())); |
| } |
| |
| void HandleWriteNvram(uint32_t index, const std::string& data) { |
| WriteNvramRequest request; |
| request.set_index(index); |
| request.set_data(data); |
| tpm_nvram_->WriteNvram( |
| request, base::Bind(&ClientLoop::PrintReplyAndQuit<WriteNvramReply>, |
| weak_factory_.GetWeakPtr())); |
| } |
| |
| void HandleReadNvram(uint32_t index) { |
| ReadNvramRequest request; |
| request.set_index(index); |
| tpm_nvram_->ReadNvram( |
| request, base::Bind(&ClientLoop::PrintReplyAndQuit<ReadNvramReply>, |
| weak_factory_.GetWeakPtr())); |
| } |
| |
| void HandleIsNvramDefined(uint32_t index) { |
| IsNvramDefinedRequest request; |
| request.set_index(index); |
| tpm_nvram_->IsNvramDefined( |
| request, base::Bind(&ClientLoop::PrintReplyAndQuit<IsNvramDefinedReply>, |
| weak_factory_.GetWeakPtr())); |
| } |
| |
| void HandleIsNvramLocked(uint32_t index) { |
| IsNvramLockedRequest request; |
| request.set_index(index); |
| tpm_nvram_->IsNvramLocked( |
| request, base::Bind(&ClientLoop::PrintReplyAndQuit<IsNvramLockedReply>, |
| weak_factory_.GetWeakPtr())); |
| } |
| |
| void HandleGetNvramSize(uint32_t index) { |
| GetNvramSizeRequest request; |
| request.set_index(index); |
| tpm_nvram_->GetNvramSize( |
| request, base::Bind(&ClientLoop::PrintReplyAndQuit<GetNvramSizeReply>, |
| weak_factory_.GetWeakPtr())); |
| } |
| |
| // Pointer to a DBus proxy to tpm_managerd. |
| std::unique_ptr<tpm_manager::TpmNvramInterface> tpm_nvram_; |
| std::unique_ptr<tpm_manager::TpmOwnershipInterface> tpm_ownership_; |
| |
| // Declared last so that weak pointers will be destroyed first. |
| base::WeakPtrFactory<ClientLoop> weak_factory_{this}; |
| |
| DISALLOW_COPY_AND_ASSIGN(ClientLoop); |
| }; |
| |
| } // namespace tpm_manager |
| |
| int main(int argc, char* argv[]) { |
| base::CommandLine::Init(argc, argv); |
| brillo::InitLog(brillo::kLogToStderr); |
| tpm_manager::ClientLoop loop; |
| return loop.Run(); |
| } |