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.
5 #include "chromeos/cryptohome/async_method_caller.h"
8 #include "base/containers/hash_tables.h"
9 #include "base/location.h"
10 #include "base/single_thread_task_runner.h"
11 #include "base/thread_task_runner_handle.h"
12 #include "chromeos/dbus/dbus_thread_manager.h"
14 using chromeos::DBusThreadManager
;
16 namespace cryptohome
{
20 AsyncMethodCaller
* g_async_method_caller
= NULL
;
22 // The implementation of AsyncMethodCaller
23 class AsyncMethodCallerImpl
: public AsyncMethodCaller
{
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()));
33 ~AsyncMethodCallerImpl() override
{
34 DBusThreadManager::Get()->GetCryptohomeClient()->
35 ResetAsyncCallStatusHandlers();
38 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(),
46 "Couldn't initiate async check of user's key."));
49 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(),
58 "Couldn't initiate aync migration of user's key"));
61 void AsyncMount(const std::string
& user_email
,
62 const std::string
& passhash
,
64 Callback callback
) override
{
65 DBusThreadManager::Get()->GetCryptohomeClient()->
66 AsyncMount(user_email
, passhash
, flags
, base::Bind(
67 &AsyncMethodCallerImpl::RegisterAsyncCallback
,
68 weak_ptr_factory_
.GetWeakPtr(),
70 "Couldn't initiate async mount of cryptohome."));
73 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(),
82 "Couldn't initiate async key addition."));
85 void AsyncMountGuest(Callback callback
) override
{
86 DBusThreadManager::Get()->GetCryptohomeClient()->
87 AsyncMountGuest(base::Bind(
88 &AsyncMethodCallerImpl::RegisterAsyncCallback
,
89 weak_ptr_factory_
.GetWeakPtr(),
91 "Couldn't initiate async mount of cryptohome."));
94 void AsyncMountPublic(const std::string
& public_mount_id
,
96 Callback callback
) override
{
97 DBusThreadManager::Get()->GetCryptohomeClient()->
98 AsyncMountPublic(public_mount_id
, flags
, base::Bind(
99 &AsyncMethodCallerImpl::RegisterAsyncCallback
,
100 weak_ptr_factory_
.GetWeakPtr(),
102 "Couldn't initiate async mount public of cryptohome."));
105 void AsyncRemove(const std::string
& user_email
, Callback callback
) override
{
106 DBusThreadManager::Get()->GetCryptohomeClient()->
107 AsyncRemove(user_email
, base::Bind(
108 &AsyncMethodCallerImpl::RegisterAsyncCallback
,
109 weak_ptr_factory_
.GetWeakPtr(),
111 "Couldn't initiate async removal of cryptohome."));
114 void AsyncTpmAttestationCreateEnrollRequest(
115 chromeos::attestation::PrivacyCAType pca_type
,
116 const DataCallback
& callback
) override
{
117 DBusThreadManager::Get()->GetCryptohomeClient()->
118 AsyncTpmAttestationCreateEnrollRequest(pca_type
, base::Bind(
119 &AsyncMethodCallerImpl::RegisterAsyncDataCallback
,
120 weak_ptr_factory_
.GetWeakPtr(),
122 "Couldn't initiate async attestation enroll request."));
125 void AsyncTpmAttestationEnroll(chromeos::attestation::PrivacyCAType pca_type
,
126 const std::string
& pca_response
,
127 const Callback
& callback
) override
{
128 DBusThreadManager::Get()->GetCryptohomeClient()->
129 AsyncTpmAttestationEnroll(pca_type
, pca_response
, base::Bind(
130 &AsyncMethodCallerImpl::RegisterAsyncCallback
,
131 weak_ptr_factory_
.GetWeakPtr(),
133 "Couldn't initiate async attestation enroll."));
136 void AsyncTpmAttestationCreateCertRequest(
137 chromeos::attestation::PrivacyCAType pca_type
,
138 chromeos::attestation::AttestationCertificateProfile certificate_profile
,
139 const std::string
& user_id
,
140 const std::string
& request_origin
,
141 const DataCallback
& callback
) override
{
142 DBusThreadManager::Get()->GetCryptohomeClient()->
143 AsyncTpmAttestationCreateCertRequest(
148 base::Bind(&AsyncMethodCallerImpl::RegisterAsyncDataCallback
,
149 weak_ptr_factory_
.GetWeakPtr(),
151 "Couldn't initiate async attestation cert request."));
154 void AsyncTpmAttestationFinishCertRequest(
155 const std::string
& pca_response
,
156 chromeos::attestation::AttestationKeyType key_type
,
157 const std::string
& user_id
,
158 const std::string
& key_name
,
159 const DataCallback
& callback
) override
{
160 DBusThreadManager::Get()->GetCryptohomeClient()->
161 AsyncTpmAttestationFinishCertRequest(
167 &AsyncMethodCallerImpl::RegisterAsyncDataCallback
,
168 weak_ptr_factory_
.GetWeakPtr(),
170 "Couldn't initiate async attestation finish cert request."));
173 void TpmAttestationRegisterKey(
174 chromeos::attestation::AttestationKeyType key_type
,
175 const std::string
& user_id
,
176 const std::string
& key_name
,
177 const Callback
& callback
) override
{
178 DBusThreadManager::Get()->GetCryptohomeClient()->
179 TpmAttestationRegisterKey(
184 &AsyncMethodCallerImpl::RegisterAsyncCallback
,
185 weak_ptr_factory_
.GetWeakPtr(),
187 "Couldn't initiate async attestation register key."));
190 void TpmAttestationSignEnterpriseChallenge(
191 chromeos::attestation::AttestationKeyType key_type
,
192 const std::string
& user_id
,
193 const std::string
& key_name
,
194 const std::string
& domain
,
195 const std::string
& device_id
,
196 chromeos::attestation::AttestationChallengeOptions options
,
197 const std::string
& challenge
,
198 const DataCallback
& callback
) override
{
199 DBusThreadManager::Get()->GetCryptohomeClient()->
200 TpmAttestationSignEnterpriseChallenge(
209 &AsyncMethodCallerImpl::RegisterAsyncDataCallback
,
210 weak_ptr_factory_
.GetWeakPtr(),
212 "Couldn't initiate async attestation enterprise challenge."));
215 void TpmAttestationSignSimpleChallenge(
216 chromeos::attestation::AttestationKeyType key_type
,
217 const std::string
& user_id
,
218 const std::string
& key_name
,
219 const std::string
& challenge
,
220 const DataCallback
& callback
) override
{
221 DBusThreadManager::Get()->GetCryptohomeClient()->
222 TpmAttestationSignSimpleChallenge(
228 &AsyncMethodCallerImpl::RegisterAsyncDataCallback
,
229 weak_ptr_factory_
.GetWeakPtr(),
231 "Couldn't initiate async attestation simple challenge."));
234 void AsyncGetSanitizedUsername(const std::string
& user
,
235 const DataCallback
& callback
) override
{
236 DBusThreadManager::Get()->GetCryptohomeClient()->
237 GetSanitizedUsername(user
,
239 &AsyncMethodCallerImpl::GetSanitizedUsernameCallback
,
240 weak_ptr_factory_
.GetWeakPtr(),
244 virtual void GetSanitizedUsernameCallback(
245 const DataCallback
& callback
,
246 const chromeos::DBusMethodCallStatus call_status
,
247 const std::string
& result
) {
248 callback
.Run(true, result
);
252 struct CallbackElement
{
254 explicit CallbackElement(const AsyncMethodCaller::Callback
& callback
)
255 : callback(callback
),
256 task_runner(base::ThreadTaskRunnerHandle::Get()) {}
257 AsyncMethodCaller::Callback callback
;
258 scoped_refptr
<base::SingleThreadTaskRunner
> task_runner
;
261 struct DataCallbackElement
{
262 DataCallbackElement() {}
263 explicit DataCallbackElement(
264 const AsyncMethodCaller::DataCallback
& callback
)
265 : data_callback(callback
),
266 task_runner(base::ThreadTaskRunnerHandle::Get()) {}
267 AsyncMethodCaller::DataCallback data_callback
;
268 scoped_refptr
<base::SingleThreadTaskRunner
> task_runner
;
271 typedef base::hash_map
<int, CallbackElement
> CallbackMap
;
272 typedef base::hash_map
<int, DataCallbackElement
> DataCallbackMap
;
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
279 // 3. Cryptohome will return the result asynchronously as a signal with
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
;
289 it
->second
.task_runner
->PostTask(
290 FROM_HERE
, base::Bind(it
->second
.callback
, return_status
,
291 static_cast<MountError
>(return_code
)));
292 callback_map_
.erase(it
);
295 // Similar to HandleAsyncResponse but for signals with a raw data payload.
296 void HandleAsyncDataResponse(int async_id
,
298 const std::string
& return_data
) {
299 const DataCallbackMap::iterator it
= data_callback_map_
.find(async_id
);
300 if (it
== data_callback_map_
.end()) {
301 LOG(ERROR
) << "Received signal for unknown async_id " << async_id
;
304 it
->second
.task_runner
->PostTask(
306 base::Bind(it
->second
.data_callback
, return_status
, return_data
));
307 data_callback_map_
.erase(it
);
309 // Registers a callback which is called when the result for AsyncXXX is ready.
310 void RegisterAsyncCallback(
311 Callback callback
, const char* error
, int async_id
) {
312 if (async_id
== chromeos::CryptohomeClient::kNotReadyAsyncId
) {
313 base::ThreadTaskRunnerHandle::Get()->PostTask(
314 FROM_HERE
, base::Bind(callback
,
315 false, // return status
316 cryptohome::MOUNT_ERROR_FATAL
));
324 VLOG(1) << "Adding handler for " << async_id
;
325 DCHECK_EQ(callback_map_
.count(async_id
), 0U);
326 DCHECK_EQ(data_callback_map_
.count(async_id
), 0U);
327 callback_map_
[async_id
] = CallbackElement(callback
);
330 // Registers a callback which is called when the result for AsyncXXX is ready.
331 void RegisterAsyncDataCallback(
332 DataCallback callback
, const char* error
, int async_id
) {
333 if (async_id
== chromeos::CryptohomeClient::kNotReadyAsyncId
) {
334 base::ThreadTaskRunnerHandle::Get()->PostTask(
335 FROM_HERE
, base::Bind(callback
,
336 false, // return status
344 VLOG(1) << "Adding handler for " << async_id
;
345 DCHECK_EQ(callback_map_
.count(async_id
), 0U);
346 DCHECK_EQ(data_callback_map_
.count(async_id
), 0U);
347 data_callback_map_
[async_id
] = DataCallbackElement(callback
);
350 CallbackMap callback_map_
;
351 DataCallbackMap data_callback_map_
;
352 base::WeakPtrFactory
<AsyncMethodCallerImpl
> weak_ptr_factory_
;
354 DISALLOW_COPY_AND_ASSIGN(AsyncMethodCallerImpl
);
360 void AsyncMethodCaller::Initialize() {
361 if (g_async_method_caller
) {
362 LOG(WARNING
) << "AsyncMethodCaller was already initialized";
365 g_async_method_caller
= new AsyncMethodCallerImpl();
366 VLOG(1) << "AsyncMethodCaller initialized";
370 void AsyncMethodCaller::InitializeForTesting(
371 AsyncMethodCaller
* async_method_caller
) {
372 if (g_async_method_caller
) {
373 LOG(WARNING
) << "AsyncMethodCaller was already initialized";
376 g_async_method_caller
= async_method_caller
;
377 VLOG(1) << "AsyncMethodCaller initialized";
381 void AsyncMethodCaller::Shutdown() {
382 if (!g_async_method_caller
) {
383 LOG(WARNING
) << "AsyncMethodCaller::Shutdown() called with NULL manager";
386 delete g_async_method_caller
;
387 g_async_method_caller
= NULL
;
388 VLOG(1) << "AsyncMethodCaller Shutdown completed";
392 AsyncMethodCaller
* AsyncMethodCaller::GetInstance() {
393 return g_async_method_caller
;
396 } // namespace cryptohome