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