1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chromeos/cryptohome/async_method_caller.h" 6 7 #include "base/bind.h" 8 #include "base/containers/hash_tables.h" 9 #include "base/location.h" 10 #include "base/message_loop/message_loop_proxy.h" 11 #include "chromeos/dbus/cryptohome_client.h" 12 #include "chromeos/dbus/dbus_thread_manager.h" 13 14 using chromeos::DBusThreadManager; 15 16 namespace cryptohome { 17 18 namespace { 19 20 AsyncMethodCaller* g_async_method_caller = NULL; 21 22 // The implementation of AsyncMethodCaller 23 class AsyncMethodCallerImpl : public AsyncMethodCaller { 24 public: 25 AsyncMethodCallerImpl() : weak_ptr_factory_(this) { 26 DBusThreadManager::Get()->GetCryptohomeClient()->SetAsyncCallStatusHandlers( 27 base::Bind(&AsyncMethodCallerImpl::HandleAsyncResponse, 28 weak_ptr_factory_.GetWeakPtr()), 29 base::Bind(&AsyncMethodCallerImpl::HandleAsyncDataResponse, 30 weak_ptr_factory_.GetWeakPtr())); 31 } 32 33 virtual ~AsyncMethodCallerImpl() { 34 DBusThreadManager::Get()->GetCryptohomeClient()-> 35 ResetAsyncCallStatusHandlers(); 36 } 37 38 virtual void AsyncCheckKey(const std::string& user_email, 39 const std::string& passhash, 40 Callback callback) OVERRIDE { 41 DBusThreadManager::Get()->GetCryptohomeClient()-> 42 AsyncCheckKey(user_email, passhash, base::Bind( 43 &AsyncMethodCallerImpl::RegisterAsyncCallback, 44 weak_ptr_factory_.GetWeakPtr(), 45 callback, 46 "Couldn't initiate async check of user's key.")); 47 } 48 49 virtual void AsyncMigrateKey(const std::string& user_email, 50 const std::string& old_hash, 51 const std::string& new_hash, 52 Callback callback) OVERRIDE { 53 DBusThreadManager::Get()->GetCryptohomeClient()-> 54 AsyncMigrateKey(user_email, old_hash, new_hash, base::Bind( 55 &AsyncMethodCallerImpl::RegisterAsyncCallback, 56 weak_ptr_factory_.GetWeakPtr(), 57 callback, 58 "Couldn't initiate aync migration of user's key")); 59 } 60 61 virtual void AsyncMount(const std::string& user_email, 62 const std::string& passhash, 63 int flags, 64 Callback callback) OVERRIDE { 65 DBusThreadManager::Get()->GetCryptohomeClient()-> 66 AsyncMount(user_email, passhash, flags, base::Bind( 67 &AsyncMethodCallerImpl::RegisterAsyncCallback, 68 weak_ptr_factory_.GetWeakPtr(), 69 callback, 70 "Couldn't initiate async mount of cryptohome.")); 71 } 72 73 virtual void AsyncAddKey(const std::string& user_email, 74 const std::string& passhash, 75 const std::string& new_passhash, 76 Callback callback) OVERRIDE { 77 DBusThreadManager::Get()->GetCryptohomeClient()-> 78 AsyncAddKey(user_email, passhash, new_passhash, base::Bind( 79 &AsyncMethodCallerImpl::RegisterAsyncCallback, 80 weak_ptr_factory_.GetWeakPtr(), 81 callback, 82 "Couldn't initiate async key addition.")); 83 } 84 85 virtual void AsyncMountGuest(Callback callback) OVERRIDE { 86 DBusThreadManager::Get()->GetCryptohomeClient()-> 87 AsyncMountGuest(base::Bind( 88 &AsyncMethodCallerImpl::RegisterAsyncCallback, 89 weak_ptr_factory_.GetWeakPtr(), 90 callback, 91 "Couldn't initiate async mount of cryptohome.")); 92 } 93 94 virtual void AsyncMountPublic(const std::string& public_mount_id, 95 int flags, 96 Callback callback) OVERRIDE { 97 DBusThreadManager::Get()->GetCryptohomeClient()-> 98 AsyncMountPublic(public_mount_id, flags, base::Bind( 99 &AsyncMethodCallerImpl::RegisterAsyncCallback, 100 weak_ptr_factory_.GetWeakPtr(), 101 callback, 102 "Couldn't initiate async mount public of cryptohome.")); 103 } 104 105 virtual void AsyncRemove(const std::string& user_email, 106 Callback callback) OVERRIDE { 107 DBusThreadManager::Get()->GetCryptohomeClient()-> 108 AsyncRemove(user_email, base::Bind( 109 &AsyncMethodCallerImpl::RegisterAsyncCallback, 110 weak_ptr_factory_.GetWeakPtr(), 111 callback, 112 "Couldn't initiate async removal of cryptohome.")); 113 } 114 115 virtual void AsyncTpmAttestationCreateEnrollRequest( 116 const DataCallback& callback) OVERRIDE { 117 DBusThreadManager::Get()->GetCryptohomeClient()-> 118 AsyncTpmAttestationCreateEnrollRequest(base::Bind( 119 &AsyncMethodCallerImpl::RegisterAsyncDataCallback, 120 weak_ptr_factory_.GetWeakPtr(), 121 callback, 122 "Couldn't initiate async attestation enroll request.")); 123 } 124 125 virtual void AsyncTpmAttestationEnroll(const std::string& pca_response, 126 const Callback& callback) OVERRIDE { 127 DBusThreadManager::Get()->GetCryptohomeClient()-> 128 AsyncTpmAttestationEnroll(pca_response, base::Bind( 129 &AsyncMethodCallerImpl::RegisterAsyncCallback, 130 weak_ptr_factory_.GetWeakPtr(), 131 callback, 132 "Couldn't initiate async attestation enroll.")); 133 } 134 135 virtual void AsyncTpmAttestationCreateCertRequest( 136 int options, 137 const DataCallback& callback) OVERRIDE { 138 DBusThreadManager::Get()->GetCryptohomeClient()-> 139 AsyncTpmAttestationCreateCertRequest( 140 options, 141 base::Bind(&AsyncMethodCallerImpl::RegisterAsyncDataCallback, 142 weak_ptr_factory_.GetWeakPtr(), 143 callback, 144 "Couldn't initiate async attestation cert request.")); 145 } 146 147 virtual void AsyncTpmAttestationFinishCertRequest( 148 const std::string& pca_response, 149 chromeos::attestation::AttestationKeyType key_type, 150 const std::string& key_name, 151 const DataCallback& callback) OVERRIDE { 152 DBusThreadManager::Get()->GetCryptohomeClient()-> 153 AsyncTpmAttestationFinishCertRequest( 154 pca_response, 155 key_type, 156 key_name, 157 base::Bind( 158 &AsyncMethodCallerImpl::RegisterAsyncDataCallback, 159 weak_ptr_factory_.GetWeakPtr(), 160 callback, 161 "Couldn't initiate async attestation finish cert request.")); 162 } 163 164 virtual void TpmAttestationRegisterKey( 165 chromeos::attestation::AttestationKeyType key_type, 166 const std::string& key_name, 167 const Callback& callback) OVERRIDE { 168 DBusThreadManager::Get()->GetCryptohomeClient()-> 169 TpmAttestationRegisterKey( 170 key_type, 171 key_name, 172 base::Bind( 173 &AsyncMethodCallerImpl::RegisterAsyncCallback, 174 weak_ptr_factory_.GetWeakPtr(), 175 callback, 176 "Couldn't initiate async attestation register key.")); 177 } 178 179 virtual void TpmAttestationSignEnterpriseChallenge( 180 chromeos::attestation::AttestationKeyType key_type, 181 const std::string& key_name, 182 const std::string& domain, 183 const std::string& device_id, 184 chromeos::attestation::AttestationChallengeOptions options, 185 const std::string& challenge, 186 const DataCallback& callback) OVERRIDE { 187 DBusThreadManager::Get()->GetCryptohomeClient()-> 188 TpmAttestationSignEnterpriseChallenge( 189 key_type, 190 key_name, 191 domain, 192 device_id, 193 options, 194 challenge, 195 base::Bind( 196 &AsyncMethodCallerImpl::RegisterAsyncDataCallback, 197 weak_ptr_factory_.GetWeakPtr(), 198 callback, 199 "Couldn't initiate async attestation enterprise challenge.")); 200 } 201 202 virtual void TpmAttestationSignSimpleChallenge( 203 chromeos::attestation::AttestationKeyType key_type, 204 const std::string& key_name, 205 const std::string& challenge, 206 const DataCallback& callback) OVERRIDE { 207 DBusThreadManager::Get()->GetCryptohomeClient()-> 208 TpmAttestationSignSimpleChallenge( 209 key_type, 210 key_name, 211 challenge, 212 base::Bind( 213 &AsyncMethodCallerImpl::RegisterAsyncDataCallback, 214 weak_ptr_factory_.GetWeakPtr(), 215 callback, 216 "Couldn't initiate async attestation simple challenge.")); 217 } 218 219 virtual void AsyncGetSanitizedUsername( 220 const std::string& user, 221 const DataCallback& callback) OVERRIDE { 222 DBusThreadManager::Get()->GetCryptohomeClient()-> 223 GetSanitizedUsername(user, 224 base::Bind( 225 &AsyncMethodCallerImpl::GetSanitizedUsernameCallback, 226 weak_ptr_factory_.GetWeakPtr(), 227 callback)); 228 } 229 230 virtual void GetSanitizedUsernameCallback( 231 const DataCallback& callback, 232 const chromeos::DBusMethodCallStatus call_status, 233 const std::string& result) { 234 callback.Run(true, result); 235 } 236 237 private: 238 struct CallbackElement { 239 CallbackElement() {} 240 explicit CallbackElement(const AsyncMethodCaller::Callback& callback) 241 : callback(callback), 242 proxy(base::MessageLoopProxy::current()) { 243 } 244 AsyncMethodCaller::Callback callback; 245 scoped_refptr<base::MessageLoopProxy> proxy; 246 }; 247 248 struct DataCallbackElement { 249 DataCallbackElement() {} 250 explicit DataCallbackElement( 251 const AsyncMethodCaller::DataCallback& callback) 252 : data_callback(callback), 253 proxy(base::MessageLoopProxy::current()) { 254 } 255 AsyncMethodCaller::DataCallback data_callback; 256 scoped_refptr<base::MessageLoopProxy> proxy; 257 }; 258 259 typedef base::hash_map<int, CallbackElement> CallbackMap; 260 typedef base::hash_map<int, DataCallbackElement> DataCallbackMap; 261 262 // Handles the response for async calls. 263 // Below is described how async calls work. 264 // 1. CryptohomeClient::AsyncXXX returns "async ID". 265 // 2. RegisterAsyncCallback registers the "async ID" with the user-provided 266 // callback. 267 // 3. Cryptohome will return the result asynchronously as a signal with 268 // "async ID" 269 // 4. "HandleAsyncResponse" handles the result signal and call the registered 270 // callback associated with the "async ID". 271 void HandleAsyncResponse(int async_id, bool return_status, int return_code) { 272 const CallbackMap::iterator it = callback_map_.find(async_id); 273 if (it == callback_map_.end()) { 274 LOG(ERROR) << "Received signal for unknown async_id " << async_id; 275 return; 276 } 277 it->second.proxy->PostTask(FROM_HERE, 278 base::Bind(it->second.callback, 279 return_status, 280 static_cast<MountError>(return_code))); 281 callback_map_.erase(it); 282 } 283 284 // Similar to HandleAsyncResponse but for signals with a raw data payload. 285 void HandleAsyncDataResponse(int async_id, 286 bool return_status, 287 const std::string& return_data) { 288 const DataCallbackMap::iterator it = data_callback_map_.find(async_id); 289 if (it == data_callback_map_.end()) { 290 LOG(ERROR) << "Received signal for unknown async_id " << async_id; 291 return; 292 } 293 it->second.proxy->PostTask(FROM_HERE, 294 base::Bind(it->second.data_callback, return_status, return_data)); 295 data_callback_map_.erase(it); 296 } 297 298 // Registers a callback which is called when the result for AsyncXXX is ready. 299 void RegisterAsyncCallback( 300 Callback callback, const char* error, int async_id) { 301 if (async_id == 0) { 302 LOG(ERROR) << error; 303 return; 304 } 305 VLOG(1) << "Adding handler for " << async_id; 306 DCHECK_EQ(callback_map_.count(async_id), 0U); 307 DCHECK_EQ(data_callback_map_.count(async_id), 0U); 308 callback_map_[async_id] = CallbackElement(callback); 309 } 310 311 // Registers a callback which is called when the result for AsyncXXX is ready. 312 void RegisterAsyncDataCallback( 313 DataCallback callback, const char* error, int async_id) { 314 if (async_id == 0) { 315 LOG(ERROR) << error; 316 return; 317 } 318 VLOG(1) << "Adding handler for " << async_id; 319 DCHECK_EQ(callback_map_.count(async_id), 0U); 320 DCHECK_EQ(data_callback_map_.count(async_id), 0U); 321 data_callback_map_[async_id] = DataCallbackElement(callback); 322 } 323 324 base::WeakPtrFactory<AsyncMethodCallerImpl> weak_ptr_factory_; 325 CallbackMap callback_map_; 326 DataCallbackMap data_callback_map_; 327 328 DISALLOW_COPY_AND_ASSIGN(AsyncMethodCallerImpl); 329 }; 330 331 } // namespace 332 333 // static 334 void AsyncMethodCaller::Initialize() { 335 if (g_async_method_caller) { 336 LOG(WARNING) << "AsyncMethodCaller was already initialized"; 337 return; 338 } 339 g_async_method_caller = new AsyncMethodCallerImpl(); 340 VLOG(1) << "AsyncMethodCaller initialized"; 341 } 342 343 // static 344 void AsyncMethodCaller::InitializeForTesting( 345 AsyncMethodCaller* async_method_caller) { 346 if (g_async_method_caller) { 347 LOG(WARNING) << "AsyncMethodCaller was already initialized"; 348 return; 349 } 350 g_async_method_caller = async_method_caller; 351 VLOG(1) << "AsyncMethodCaller initialized"; 352 } 353 354 // static 355 void AsyncMethodCaller::Shutdown() { 356 if (!g_async_method_caller) { 357 LOG(WARNING) << "AsyncMethodCaller::Shutdown() called with NULL manager"; 358 return; 359 } 360 delete g_async_method_caller; 361 g_async_method_caller = NULL; 362 VLOG(1) << "AsyncMethodCaller Shutdown completed"; 363 } 364 365 // static 366 AsyncMethodCaller* AsyncMethodCaller::GetInstance() { 367 return g_async_method_caller; 368 } 369 370 } // namespace cryptohome 371