1 // 2 // Copyright (C) 2015 The Android Open Source Project 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 // 16 17 #include <stdio.h> 18 #include <stdlib.h> 19 #include <sysexits.h> 20 21 #include <memory> 22 #include <string> 23 24 #include <base/command_line.h> 25 #include <base/logging.h> 26 #include <base/message_loop/message_loop.h> 27 #include <brillo/bind_lambda.h> 28 #include <brillo/daemons/daemon.h> 29 #include <brillo/syslog_logging.h> 30 31 #include "tpm_manager/client/tpm_nvram_dbus_proxy.h" 32 #include "tpm_manager/client/tpm_ownership_dbus_proxy.h" 33 #include "tpm_manager/common/print_tpm_ownership_interface_proto.h" 34 #include "tpm_manager/common/print_tpm_nvram_interface_proto.h" 35 #include "tpm_manager/common/tpm_ownership_interface.pb.h" 36 #include "tpm_manager/common/tpm_nvram_interface.pb.h" 37 38 namespace tpm_manager { 39 40 const char kGetTpmStatusCommand[] = "status"; 41 const char kTakeOwnershipCommand[] = "take_ownership"; 42 const char kRemoveOwnerDependencyCommand[] = "remove_dependency"; 43 const char kDefineNvramCommand[] = "define_nvram"; 44 const char kDestroyNvramCommand[] = "destroy_nvram"; 45 const char kWriteNvramCommand[] = "write_nvram"; 46 const char kReadNvramCommand[] = "read_nvram"; 47 const char kIsNvramDefinedCommand[] = "is_nvram_defined"; 48 const char kIsNvramLockedCommand[] = "is_nvram_locked"; 49 const char kGetNvramSizeCommand[] = "get_nvram_size"; 50 51 const char kNvramIndexArg[] = "nvram_index"; 52 const char kNvramLengthArg[] = "nvram_length"; 53 const char kNvramDataArg[] = "nvram_data"; 54 55 const char kUsage[] = R"( 56 Usage: tpm_manager_client <command> [<arguments>] 57 Commands (used as switches): 58 --status 59 Prints the current status of the Tpm. 60 --take_ownership 61 Takes ownership of the Tpm with a random password. 62 --remove_dependency=<owner_dependency> 63 Removes the provided Tpm owner dependency. 64 --define_nvram 65 Defines an NV space at |nvram_index| with length |nvram_length|. 66 --destroy_nvram 67 Destroys the NV space at |nvram_index|. 68 --write_nvram 69 Writes the NV space at |nvram_index| with |nvram_data|. 70 --read_nvram 71 Prints the contents of the NV space at |nvram_index|. 72 --is_nvram_defined 73 Prints whether the NV space at |nvram_index| is defined. 74 --is_nvram_locked 75 Prints whether the NV space at |nvram_index| is locked for writing. 76 --get_nvram_size 77 Prints the size of the NV space at |nvram_index|. 78 Arguments (used as switches): 79 --nvram_index=<index> 80 Index of NV space to operate on. 81 --nvram_length=<length> 82 Size in bytes of the NV space to be created. 83 --nvram_data=<data> 84 Data to write to NV space. 85 )"; 86 87 using ClientLoopBase = brillo::Daemon; 88 class ClientLoop : public ClientLoopBase { 89 public: 90 ClientLoop() = default; 91 ~ClientLoop() override = default; 92 93 protected: 94 int OnInit() override { 95 int exit_code = ClientLoopBase::OnInit(); 96 if (exit_code != EX_OK) { 97 LOG(ERROR) << "Error initializing tpm_manager_client."; 98 return exit_code; 99 } 100 TpmNvramDBusProxy* nvram_proxy = new TpmNvramDBusProxy(); 101 if (!nvram_proxy->Initialize()) { 102 LOG(ERROR) << "Error initializing proxy to nvram interface."; 103 return EX_UNAVAILABLE; 104 } 105 TpmOwnershipDBusProxy* ownership_proxy = new TpmOwnershipDBusProxy(); 106 if (!ownership_proxy->Initialize()) { 107 LOG(ERROR) << "Error initializing proxy to ownership interface."; 108 return EX_UNAVAILABLE; 109 } 110 tpm_nvram_.reset(nvram_proxy); 111 tpm_ownership_.reset(ownership_proxy); 112 exit_code = ScheduleCommand(); 113 if (exit_code == EX_USAGE) { 114 printf("%s", kUsage); 115 } 116 return exit_code; 117 } 118 119 void OnShutdown(int* exit_code) override { 120 tpm_nvram_.reset(); 121 tpm_ownership_.reset(); 122 ClientLoopBase::OnShutdown(exit_code); 123 } 124 125 private: 126 // Posts tasks on to the message loop based on command line flags. 127 int ScheduleCommand() { 128 base::Closure task; 129 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); 130 if (command_line->HasSwitch("help") || command_line->HasSwitch("h")) { 131 return EX_USAGE; 132 } else if (command_line->HasSwitch(kGetTpmStatusCommand)) { 133 task = base::Bind(&ClientLoop::HandleGetTpmStatus, 134 weak_factory_.GetWeakPtr()); 135 } else if (command_line->HasSwitch(kTakeOwnershipCommand)) { 136 task = base::Bind(&ClientLoop::HandleTakeOwnership, 137 weak_factory_.GetWeakPtr()); 138 } else if (command_line->HasSwitch(kRemoveOwnerDependencyCommand)) { 139 task = base::Bind( 140 &ClientLoop::HandleRemoveOwnerDependency, 141 weak_factory_.GetWeakPtr(), 142 command_line->GetSwitchValueASCII(kRemoveOwnerDependencyCommand)); 143 } else if (command_line->HasSwitch(kDefineNvramCommand)) { 144 if (!command_line->HasSwitch(kNvramIndexArg) || 145 !command_line->HasSwitch(kNvramLengthArg)) { 146 LOG(ERROR) << "Cannot define nvram without a valid index and length."; 147 return EX_USAGE; 148 } 149 task = base::Bind( 150 &ClientLoop::HandleDefineNvram, 151 weak_factory_.GetWeakPtr(), 152 atoi(command_line->GetSwitchValueASCII(kNvramIndexArg).c_str()), 153 atoi(command_line->GetSwitchValueASCII(kNvramLengthArg).c_str())); 154 } else if (command_line->HasSwitch(kDestroyNvramCommand)) { 155 if (!command_line->HasSwitch(kNvramIndexArg)) { 156 LOG(ERROR) << "Cannot destroy nvram without a valid index."; 157 return EX_USAGE; 158 } 159 task = base::Bind( 160 &ClientLoop::HandleDestroyNvram, 161 weak_factory_.GetWeakPtr(), 162 atoi(command_line->GetSwitchValueASCII(kNvramIndexArg).c_str())); 163 } else if (command_line->HasSwitch(kWriteNvramCommand)) { 164 if (!command_line->HasSwitch(kNvramIndexArg) || 165 !command_line->HasSwitch(kNvramDataArg)) { 166 LOG(ERROR) << "Cannot write nvram without a valid index and data."; 167 return EX_USAGE; 168 } 169 task = base::Bind( 170 &ClientLoop::HandleWriteNvram, 171 weak_factory_.GetWeakPtr(), 172 atoi(command_line->GetSwitchValueASCII(kNvramIndexArg).c_str()), 173 command_line->GetSwitchValueASCII(kNvramDataArg)); 174 } else if (command_line->HasSwitch(kReadNvramCommand)) { 175 if (!command_line->HasSwitch(kNvramIndexArg)) { 176 LOG(ERROR) << "Cannot read nvram without a valid index."; 177 return EX_USAGE; 178 } 179 task = base::Bind( 180 &ClientLoop::HandleReadNvram, 181 weak_factory_.GetWeakPtr(), 182 atoi(command_line->GetSwitchValueASCII(kNvramIndexArg).c_str())); 183 } else if (command_line->HasSwitch(kIsNvramDefinedCommand)) { 184 if (!command_line->HasSwitch(kNvramIndexArg)) { 185 LOG(ERROR) << "Cannot query nvram without a valid index."; 186 return EX_USAGE; 187 } 188 task = base::Bind( 189 &ClientLoop::HandleIsNvramDefined, 190 weak_factory_.GetWeakPtr(), 191 atoi(command_line->GetSwitchValueASCII(kNvramIndexArg).c_str())); 192 } else if (command_line->HasSwitch(kIsNvramLockedCommand)) { 193 if (!command_line->HasSwitch(kNvramIndexArg)) { 194 LOG(ERROR) << "Cannot query nvram without a valid index."; 195 return EX_USAGE; 196 } 197 task = base::Bind( 198 &ClientLoop::HandleIsNvramLocked, 199 weak_factory_.GetWeakPtr(), 200 atoi(command_line->GetSwitchValueASCII(kNvramIndexArg).c_str())); 201 } else if (command_line->HasSwitch(kGetNvramSizeCommand)) { 202 if (!command_line->HasSwitch(kNvramIndexArg)) { 203 LOG(ERROR) << "Cannot query nvram without a valid index."; 204 return EX_USAGE; 205 } 206 task = base::Bind( 207 &ClientLoop::HandleGetNvramSize, 208 weak_factory_.GetWeakPtr(), 209 atoi(command_line->GetSwitchValueASCII(kNvramIndexArg).c_str())); 210 } else { 211 // Command line arguments did not match any valid commands. 212 LOG(ERROR) << "No Valid Command selected."; 213 return EX_USAGE; 214 } 215 base::MessageLoop::current()->PostTask(FROM_HERE, task); 216 return EX_OK; 217 } 218 219 // Template to print reply protobuf. 220 template <typename ProtobufType> 221 void PrintReplyAndQuit(const ProtobufType& reply) { 222 LOG(INFO) << "Message Reply: " << GetProtoDebugString(reply); 223 Quit(); 224 } 225 226 void HandleGetTpmStatus() { 227 GetTpmStatusRequest request; 228 tpm_ownership_->GetTpmStatus( 229 request, 230 base::Bind(&ClientLoop::PrintReplyAndQuit<GetTpmStatusReply>, 231 weak_factory_.GetWeakPtr())); 232 } 233 234 void HandleTakeOwnership() { 235 TakeOwnershipRequest request; 236 tpm_ownership_->TakeOwnership( 237 request, 238 base::Bind(&ClientLoop::PrintReplyAndQuit<TakeOwnershipReply>, 239 weak_factory_.GetWeakPtr())); 240 } 241 242 void HandleRemoveOwnerDependency(const std::string& owner_dependency) { 243 RemoveOwnerDependencyRequest request; 244 request.set_owner_dependency(owner_dependency); 245 tpm_ownership_->RemoveOwnerDependency( 246 request, 247 base::Bind(&ClientLoop::PrintReplyAndQuit<RemoveOwnerDependencyReply>, 248 weak_factory_.GetWeakPtr())); 249 } 250 251 void HandleDefineNvram(uint32_t index, size_t length) { 252 DefineNvramRequest request; 253 request.set_index(index); 254 request.set_length(length); 255 tpm_nvram_->DefineNvram( 256 request, 257 base::Bind(&ClientLoop::PrintReplyAndQuit<DefineNvramReply>, 258 weak_factory_.GetWeakPtr())); 259 } 260 261 void HandleDestroyNvram(uint32_t index) { 262 DestroyNvramRequest request; 263 request.set_index(index); 264 tpm_nvram_->DestroyNvram( 265 request, 266 base::Bind(&ClientLoop::PrintReplyAndQuit<DestroyNvramReply>, 267 weak_factory_.GetWeakPtr())); 268 } 269 270 void HandleWriteNvram(uint32_t index, const std::string& data) { 271 WriteNvramRequest request; 272 request.set_index(index); 273 request.set_data(data); 274 tpm_nvram_->WriteNvram( 275 request, 276 base::Bind(&ClientLoop::PrintReplyAndQuit<WriteNvramReply>, 277 weak_factory_.GetWeakPtr())); 278 } 279 280 void HandleReadNvram(uint32_t index) { 281 ReadNvramRequest request; 282 request.set_index(index); 283 tpm_nvram_->ReadNvram( 284 request, 285 base::Bind(&ClientLoop::PrintReplyAndQuit<ReadNvramReply>, 286 weak_factory_.GetWeakPtr())); 287 } 288 289 void HandleIsNvramDefined(uint32_t index) { 290 IsNvramDefinedRequest request; 291 request.set_index(index); 292 tpm_nvram_->IsNvramDefined( 293 request, 294 base::Bind(&ClientLoop::PrintReplyAndQuit<IsNvramDefinedReply>, 295 weak_factory_.GetWeakPtr())); 296 } 297 298 void HandleIsNvramLocked(uint32_t index) { 299 IsNvramLockedRequest request; 300 request.set_index(index); 301 tpm_nvram_->IsNvramLocked( 302 request, 303 base::Bind(&ClientLoop::PrintReplyAndQuit<IsNvramLockedReply>, 304 weak_factory_.GetWeakPtr())); 305 } 306 307 void HandleGetNvramSize(uint32_t index) { 308 GetNvramSizeRequest request; 309 request.set_index(index); 310 tpm_nvram_->GetNvramSize( 311 request, 312 base::Bind(&ClientLoop::PrintReplyAndQuit<GetNvramSizeReply>, 313 weak_factory_.GetWeakPtr())); 314 } 315 316 // Pointer to a DBus proxy to tpm_managerd. 317 std::unique_ptr<tpm_manager::TpmNvramInterface> tpm_nvram_; 318 std::unique_ptr<tpm_manager::TpmOwnershipInterface> tpm_ownership_; 319 320 // Declared last so that weak pointers will be destroyed first. 321 base::WeakPtrFactory<ClientLoop> weak_factory_{this}; 322 323 DISALLOW_COPY_AND_ASSIGN(ClientLoop); 324 }; 325 326 } // namespace tpm_manager 327 328 int main(int argc, char* argv[]) { 329 base::CommandLine::Init(argc, argv); 330 brillo::InitLog(brillo::kLogToStderr); 331 tpm_manager::ClientLoop loop; 332 return loop.Run(); 333 } 334