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 chromeos::attestation::PrivacyCAType pca_type, 117 const DataCallback& callback) OVERRIDE { 118 DBusThreadManager::Get()->GetCryptohomeClient()-> 119 AsyncTpmAttestationCreateEnrollRequest(pca_type, base::Bind( 120 &AsyncMethodCallerImpl::RegisterAsyncDataCallback, 121 weak_ptr_factory_.GetWeakPtr(), 122 callback, 123 "Couldn't initiate async attestation enroll request.")); 124 } 125 126 virtual void AsyncTpmAttestationEnroll( 127 chromeos::attestation::PrivacyCAType pca_type, 128 const std::string& pca_response, 129 const Callback& callback) OVERRIDE { 130 DBusThreadManager::Get()->GetCryptohomeClient()-> 131 AsyncTpmAttestationEnroll(pca_type, pca_response, base::Bind( 132 &AsyncMethodCallerImpl::RegisterAsyncCallback, 133 weak_ptr_factory_.GetWeakPtr(), 134 callback, 135 "Couldn't initiate async attestation enroll.")); 136 } 137 138 virtual void AsyncTpmAttestationCreateCertRequest( 139 chromeos::attestation::PrivacyCAType pca_type, 140 chromeos::attestation::AttestationCertificateProfile certificate_profile, 141 const std::string& user_id, 142 const std::string& request_origin, 143 const DataCallback& callback) OVERRIDE { 144 DBusThreadManager::Get()->GetCryptohomeClient()-> 145 AsyncTpmAttestationCreateCertRequest( 146 pca_type, 147 certificate_profile, 148 user_id, 149 request_origin, 150 base::Bind(&AsyncMethodCallerImpl::RegisterAsyncDataCallback, 151 weak_ptr_factory_.GetWeakPtr(), 152 callback, 153 "Couldn't initiate async attestation cert request.")); 154 } 155 156 virtual void AsyncTpmAttestationFinishCertRequest( 157 const std::string& pca_response, 158 chromeos::attestation::AttestationKeyType key_type, 159 const std::string& user_id, 160 const std::string& key_name, 161 const DataCallback& callback) OVERRIDE { 162 DBusThreadManager::Get()->GetCryptohomeClient()-> 163 AsyncTpmAttestationFinishCertRequest( 164 pca_response, 165 key_type, 166 user_id, 167 key_name, 168 base::Bind( 169 &AsyncMethodCallerImpl::RegisterAsyncDataCallback, 170 weak_ptr_factory_.GetWeakPtr(), 171 callback, 172 "Couldn't initiate async attestation finish cert request.")); 173 } 174 175 virtual void TpmAttestationRegisterKey( 176 chromeos::attestation::AttestationKeyType key_type, 177 const std::string& user_id, 178 const std::string& key_name, 179 const Callback& callback) OVERRIDE { 180 DBusThreadManager::Get()->GetCryptohomeClient()-> 181 TpmAttestationRegisterKey( 182 key_type, 183 user_id, 184 key_name, 185 base::Bind( 186 &AsyncMethodCallerImpl::RegisterAsyncCallback, 187 weak_ptr_factory_.GetWeakPtr(), 188 callback, 189 "Couldn't initiate async attestation register key.")); 190 } 191 192 virtual void TpmAttestationSignEnterpriseChallenge( 193 chromeos::attestation::AttestationKeyType key_type, 194 const std::string& user_id, 195 const std::string& key_name, 196 const std::string& domain, 197 const std::string& device_id, 198 chromeos::attestation::AttestationChallengeOptions options, 199 const std::string& challenge, 200 const DataCallback& callback) OVERRIDE { 201 DBusThreadManager::Get()->GetCryptohomeClient()-> 202 TpmAttestationSignEnterpriseChallenge( 203 key_type, 204 user_id, 205 key_name, 206 domain, 207 device_id, 208 options, 209 challenge, 210 base::Bind( 211 &AsyncMethodCallerImpl::RegisterAsyncDataCallback, 212 weak_ptr_factory_.GetWeakPtr(), 213 callback, 214 "Couldn't initiate async attestation enterprise challenge.")); 215 } 216 217 virtual void TpmAttestationSignSimpleChallenge( 218 chromeos::attestation::AttestationKeyType key_type, 219 const std::string& user_id, 220 const std::string& key_name, 221 const std::string& challenge, 222 const DataCallback& callback) OVERRIDE { 223 DBusThreadManager::Get()->GetCryptohomeClient()-> 224 TpmAttestationSignSimpleChallenge( 225 key_type, 226 user_id, 227 key_name, 228 challenge, 229 base::Bind( 230 &AsyncMethodCallerImpl::RegisterAsyncDataCallback, 231 weak_ptr_factory_.GetWeakPtr(), 232 callback, 233 "Couldn't initiate async attestation simple challenge.")); 234 } 235 236 virtual void AsyncGetSanitizedUsername( 237 const std::string& user, 238 const DataCallback& callback) OVERRIDE { 239 DBusThreadManager::Get()->GetCryptohomeClient()-> 240 GetSanitizedUsername(user, 241 base::Bind( 242 &AsyncMethodCallerImpl::GetSanitizedUsernameCallback, 243 weak_ptr_factory_.GetWeakPtr(), 244 callback)); 245 } 246 247 virtual void GetSanitizedUsernameCallback( 248 const DataCallback& callback, 249 const chromeos::DBusMethodCallStatus call_status, 250 const std::string& result) { 251 callback.Run(true, result); 252 } 253 254 private: 255 struct CallbackElement { 256 CallbackElement() {} 257 explicit CallbackElement(const AsyncMethodCaller::Callback& callback) 258 : callback(callback), 259 proxy(base::MessageLoopProxy::current()) { 260 } 261 AsyncMethodCaller::Callback callback; 262 scoped_refptr<base::MessageLoopProxy> proxy; 263 }; 264 265 struct DataCallbackElement { 266 DataCallbackElement() {} 267 explicit DataCallbackElement( 268 const AsyncMethodCaller::DataCallback& callback) 269 : data_callback(callback), 270 proxy(base::MessageLoopProxy::current()) { 271 } 272 AsyncMethodCaller::DataCallback data_callback; 273 scoped_refptr<base::MessageLoopProxy> proxy; 274 }; 275 276 typedef base::hash_map<int, CallbackElement> CallbackMap; 277 typedef base::hash_map<int, DataCallbackElement> DataCallbackMap; 278 279 // Handles the response for async calls. 280 // Below is described how async calls work. 281 // 1. CryptohomeClient::AsyncXXX returns "async ID". 282 // 2. RegisterAsyncCallback registers the "async ID" with the user-provided 283 // callback. 284 // 3. Cryptohome will return the result asynchronously as a signal with 285 // "async ID" 286 // 4. "HandleAsyncResponse" handles the result signal and call the registered 287 // callback associated with the "async ID". 288 void HandleAsyncResponse(int async_id, bool return_status, int return_code) { 289 const CallbackMap::iterator it = callback_map_.find(async_id); 290 if (it == callback_map_.end()) { 291 LOG(ERROR) << "Received signal for unknown async_id " << async_id; 292 return; 293 } 294 it->second.proxy->PostTask(FROM_HERE, 295 base::Bind(it->second.callback, 296 return_status, 297 static_cast<MountError>(return_code))); 298 callback_map_.erase(it); 299 } 300 301 // Similar to HandleAsyncResponse but for signals with a raw data payload. 302 void HandleAsyncDataResponse(int async_id, 303 bool return_status, 304 const std::string& return_data) { 305 const DataCallbackMap::iterator it = data_callback_map_.find(async_id); 306 if (it == data_callback_map_.end()) { 307 LOG(ERROR) << "Received signal for unknown async_id " << async_id; 308 return; 309 } 310 it->second.proxy->PostTask(FROM_HERE, 311 base::Bind(it->second.data_callback, return_status, return_data)); 312 data_callback_map_.erase(it); 313 } 314 315 // Registers a callback which is called when the result for AsyncXXX is ready. 316 void RegisterAsyncCallback( 317 Callback callback, const char* error, int async_id) { 318 if (async_id == 0) { 319 LOG(ERROR) << error; 320 return; 321 } 322 VLOG(1) << "Adding handler for " << async_id; 323 DCHECK_EQ(callback_map_.count(async_id), 0U); 324 DCHECK_EQ(data_callback_map_.count(async_id), 0U); 325 callback_map_[async_id] = CallbackElement(callback); 326 } 327 328 // Registers a callback which is called when the result for AsyncXXX is ready. 329 void RegisterAsyncDataCallback( 330 DataCallback callback, const char* error, int async_id) { 331 if (async_id == 0) { 332 LOG(ERROR) << error; 333 return; 334 } 335 VLOG(1) << "Adding handler for " << async_id; 336 DCHECK_EQ(callback_map_.count(async_id), 0U); 337 DCHECK_EQ(data_callback_map_.count(async_id), 0U); 338 data_callback_map_[async_id] = DataCallbackElement(callback); 339 } 340 341 base::WeakPtrFactory<AsyncMethodCallerImpl> weak_ptr_factory_; 342 CallbackMap callback_map_; 343 DataCallbackMap data_callback_map_; 344 345 DISALLOW_COPY_AND_ASSIGN(AsyncMethodCallerImpl); 346 }; 347 348 } // namespace 349 350 // static 351 void AsyncMethodCaller::Initialize() { 352 if (g_async_method_caller) { 353 LOG(WARNING) << "AsyncMethodCaller was already initialized"; 354 return; 355 } 356 g_async_method_caller = new AsyncMethodCallerImpl(); 357 VLOG(1) << "AsyncMethodCaller initialized"; 358 } 359 360 // static 361 void AsyncMethodCaller::InitializeForTesting( 362 AsyncMethodCaller* async_method_caller) { 363 if (g_async_method_caller) { 364 LOG(WARNING) << "AsyncMethodCaller was already initialized"; 365 return; 366 } 367 g_async_method_caller = async_method_caller; 368 VLOG(1) << "AsyncMethodCaller initialized"; 369 } 370 371 // static 372 void AsyncMethodCaller::Shutdown() { 373 if (!g_async_method_caller) { 374 LOG(WARNING) << "AsyncMethodCaller::Shutdown() called with NULL manager"; 375 return; 376 } 377 delete g_async_method_caller; 378 g_async_method_caller = NULL; 379 VLOG(1) << "AsyncMethodCaller Shutdown completed"; 380 } 381 382 // static 383 AsyncMethodCaller* AsyncMethodCaller::GetInstance() { 384 return g_async_method_caller; 385 } 386 387 } // namespace cryptohome 388