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/message_loop/message_loop_proxy.h"
11 #include "chromeos/dbus/dbus_thread_manager.h"
13 using chromeos::DBusThreadManager
;
15 namespace cryptohome
{
19 AsyncMethodCaller
* g_async_method_caller
= NULL
;
21 // The implementation of AsyncMethodCaller
22 class AsyncMethodCallerImpl
: public AsyncMethodCaller
{
24 AsyncMethodCallerImpl() : weak_ptr_factory_(this) {
25 DBusThreadManager::Get()->GetCryptohomeClient()->SetAsyncCallStatusHandlers(
26 base::Bind(&AsyncMethodCallerImpl::HandleAsyncResponse
,
27 weak_ptr_factory_
.GetWeakPtr()),
28 base::Bind(&AsyncMethodCallerImpl::HandleAsyncDataResponse
,
29 weak_ptr_factory_
.GetWeakPtr()));
32 ~AsyncMethodCallerImpl() override
{
33 DBusThreadManager::Get()->GetCryptohomeClient()->
34 ResetAsyncCallStatusHandlers();
37 void AsyncCheckKey(const std::string
& user_email
,
38 const std::string
& passhash
,
39 Callback callback
) override
{
40 DBusThreadManager::Get()->GetCryptohomeClient()->
41 AsyncCheckKey(user_email
, passhash
, base::Bind(
42 &AsyncMethodCallerImpl::RegisterAsyncCallback
,
43 weak_ptr_factory_
.GetWeakPtr(),
45 "Couldn't initiate async check of user's key."));
48 void AsyncMigrateKey(const std::string
& user_email
,
49 const std::string
& old_hash
,
50 const std::string
& new_hash
,
51 Callback callback
) override
{
52 DBusThreadManager::Get()->GetCryptohomeClient()->
53 AsyncMigrateKey(user_email
, old_hash
, new_hash
, base::Bind(
54 &AsyncMethodCallerImpl::RegisterAsyncCallback
,
55 weak_ptr_factory_
.GetWeakPtr(),
57 "Couldn't initiate aync migration of user's key"));
60 void AsyncMount(const std::string
& user_email
,
61 const std::string
& passhash
,
63 Callback callback
) override
{
64 DBusThreadManager::Get()->GetCryptohomeClient()->
65 AsyncMount(user_email
, passhash
, flags
, base::Bind(
66 &AsyncMethodCallerImpl::RegisterAsyncCallback
,
67 weak_ptr_factory_
.GetWeakPtr(),
69 "Couldn't initiate async mount of cryptohome."));
72 void AsyncAddKey(const std::string
& user_email
,
73 const std::string
& passhash
,
74 const std::string
& new_passhash
,
75 Callback callback
) override
{
76 DBusThreadManager::Get()->GetCryptohomeClient()->
77 AsyncAddKey(user_email
, passhash
, new_passhash
, base::Bind(
78 &AsyncMethodCallerImpl::RegisterAsyncCallback
,
79 weak_ptr_factory_
.GetWeakPtr(),
81 "Couldn't initiate async key addition."));
84 void AsyncMountGuest(Callback callback
) override
{
85 DBusThreadManager::Get()->GetCryptohomeClient()->
86 AsyncMountGuest(base::Bind(
87 &AsyncMethodCallerImpl::RegisterAsyncCallback
,
88 weak_ptr_factory_
.GetWeakPtr(),
90 "Couldn't initiate async mount of cryptohome."));
93 void AsyncMountPublic(const std::string
& public_mount_id
,
95 Callback callback
) override
{
96 DBusThreadManager::Get()->GetCryptohomeClient()->
97 AsyncMountPublic(public_mount_id
, flags
, base::Bind(
98 &AsyncMethodCallerImpl::RegisterAsyncCallback
,
99 weak_ptr_factory_
.GetWeakPtr(),
101 "Couldn't initiate async mount public of cryptohome."));
104 void AsyncRemove(const std::string
& user_email
, Callback callback
) override
{
105 DBusThreadManager::Get()->GetCryptohomeClient()->
106 AsyncRemove(user_email
, base::Bind(
107 &AsyncMethodCallerImpl::RegisterAsyncCallback
,
108 weak_ptr_factory_
.GetWeakPtr(),
110 "Couldn't initiate async removal of cryptohome."));
113 void AsyncTpmAttestationCreateEnrollRequest(
114 chromeos::attestation::PrivacyCAType pca_type
,
115 const DataCallback
& callback
) override
{
116 DBusThreadManager::Get()->GetCryptohomeClient()->
117 AsyncTpmAttestationCreateEnrollRequest(pca_type
, base::Bind(
118 &AsyncMethodCallerImpl::RegisterAsyncDataCallback
,
119 weak_ptr_factory_
.GetWeakPtr(),
121 "Couldn't initiate async attestation enroll request."));
124 void AsyncTpmAttestationEnroll(chromeos::attestation::PrivacyCAType pca_type
,
125 const std::string
& pca_response
,
126 const Callback
& callback
) override
{
127 DBusThreadManager::Get()->GetCryptohomeClient()->
128 AsyncTpmAttestationEnroll(pca_type
, pca_response
, base::Bind(
129 &AsyncMethodCallerImpl::RegisterAsyncCallback
,
130 weak_ptr_factory_
.GetWeakPtr(),
132 "Couldn't initiate async attestation enroll."));
135 void AsyncTpmAttestationCreateCertRequest(
136 chromeos::attestation::PrivacyCAType pca_type
,
137 chromeos::attestation::AttestationCertificateProfile certificate_profile
,
138 const std::string
& user_id
,
139 const std::string
& request_origin
,
140 const DataCallback
& callback
) override
{
141 DBusThreadManager::Get()->GetCryptohomeClient()->
142 AsyncTpmAttestationCreateCertRequest(
147 base::Bind(&AsyncMethodCallerImpl::RegisterAsyncDataCallback
,
148 weak_ptr_factory_
.GetWeakPtr(),
150 "Couldn't initiate async attestation cert request."));
153 void AsyncTpmAttestationFinishCertRequest(
154 const std::string
& pca_response
,
155 chromeos::attestation::AttestationKeyType key_type
,
156 const std::string
& user_id
,
157 const std::string
& key_name
,
158 const DataCallback
& callback
) override
{
159 DBusThreadManager::Get()->GetCryptohomeClient()->
160 AsyncTpmAttestationFinishCertRequest(
166 &AsyncMethodCallerImpl::RegisterAsyncDataCallback
,
167 weak_ptr_factory_
.GetWeakPtr(),
169 "Couldn't initiate async attestation finish cert request."));
172 void TpmAttestationRegisterKey(
173 chromeos::attestation::AttestationKeyType key_type
,
174 const std::string
& user_id
,
175 const std::string
& key_name
,
176 const Callback
& callback
) override
{
177 DBusThreadManager::Get()->GetCryptohomeClient()->
178 TpmAttestationRegisterKey(
183 &AsyncMethodCallerImpl::RegisterAsyncCallback
,
184 weak_ptr_factory_
.GetWeakPtr(),
186 "Couldn't initiate async attestation register key."));
189 void TpmAttestationSignEnterpriseChallenge(
190 chromeos::attestation::AttestationKeyType key_type
,
191 const std::string
& user_id
,
192 const std::string
& key_name
,
193 const std::string
& domain
,
194 const std::string
& device_id
,
195 chromeos::attestation::AttestationChallengeOptions options
,
196 const std::string
& challenge
,
197 const DataCallback
& callback
) override
{
198 DBusThreadManager::Get()->GetCryptohomeClient()->
199 TpmAttestationSignEnterpriseChallenge(
208 &AsyncMethodCallerImpl::RegisterAsyncDataCallback
,
209 weak_ptr_factory_
.GetWeakPtr(),
211 "Couldn't initiate async attestation enterprise challenge."));
214 void TpmAttestationSignSimpleChallenge(
215 chromeos::attestation::AttestationKeyType key_type
,
216 const std::string
& user_id
,
217 const std::string
& key_name
,
218 const std::string
& challenge
,
219 const DataCallback
& callback
) override
{
220 DBusThreadManager::Get()->GetCryptohomeClient()->
221 TpmAttestationSignSimpleChallenge(
227 &AsyncMethodCallerImpl::RegisterAsyncDataCallback
,
228 weak_ptr_factory_
.GetWeakPtr(),
230 "Couldn't initiate async attestation simple challenge."));
233 void AsyncGetSanitizedUsername(const std::string
& user
,
234 const DataCallback
& callback
) override
{
235 DBusThreadManager::Get()->GetCryptohomeClient()->
236 GetSanitizedUsername(user
,
238 &AsyncMethodCallerImpl::GetSanitizedUsernameCallback
,
239 weak_ptr_factory_
.GetWeakPtr(),
243 virtual void GetSanitizedUsernameCallback(
244 const DataCallback
& callback
,
245 const chromeos::DBusMethodCallStatus call_status
,
246 const std::string
& result
) {
247 callback
.Run(true, result
);
251 struct CallbackElement
{
253 explicit CallbackElement(const AsyncMethodCaller::Callback
& callback
)
254 : callback(callback
),
255 proxy(base::MessageLoopProxy::current()) {
257 AsyncMethodCaller::Callback callback
;
258 scoped_refptr
<base::MessageLoopProxy
> proxy
;
261 struct DataCallbackElement
{
262 DataCallbackElement() {}
263 explicit DataCallbackElement(
264 const AsyncMethodCaller::DataCallback
& callback
)
265 : data_callback(callback
),
266 proxy(base::MessageLoopProxy::current()) {
268 AsyncMethodCaller::DataCallback data_callback
;
269 scoped_refptr
<base::MessageLoopProxy
> proxy
;
272 typedef base::hash_map
<int, CallbackElement
> CallbackMap
;
273 typedef base::hash_map
<int, DataCallbackElement
> DataCallbackMap
;
275 // Handles the response for async calls.
276 // Below is described how async calls work.
277 // 1. CryptohomeClient::AsyncXXX returns "async ID".
278 // 2. RegisterAsyncCallback registers the "async ID" with the user-provided
280 // 3. Cryptohome will return the result asynchronously as a signal with
282 // 4. "HandleAsyncResponse" handles the result signal and call the registered
283 // callback associated with the "async ID".
284 void HandleAsyncResponse(int async_id
, bool return_status
, int return_code
) {
285 const CallbackMap::iterator it
= callback_map_
.find(async_id
);
286 if (it
== callback_map_
.end()) {
287 LOG(ERROR
) << "Received signal for unknown async_id " << async_id
;
290 it
->second
.proxy
->PostTask(FROM_HERE
,
291 base::Bind(it
->second
.callback
,
293 static_cast<MountError
>(return_code
)));
294 callback_map_
.erase(it
);
297 // Similar to HandleAsyncResponse but for signals with a raw data payload.
298 void HandleAsyncDataResponse(int async_id
,
300 const std::string
& return_data
) {
301 const DataCallbackMap::iterator it
= data_callback_map_
.find(async_id
);
302 if (it
== data_callback_map_
.end()) {
303 LOG(ERROR
) << "Received signal for unknown async_id " << async_id
;
306 it
->second
.proxy
->PostTask(FROM_HERE
,
307 base::Bind(it
->second
.data_callback
, return_status
, return_data
));
308 data_callback_map_
.erase(it
);
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
== chromeos::CryptohomeClient::kNotReadyAsyncId
) {
314 base::MessageLoopProxy::current()->PostTask(
315 FROM_HERE
, base::Bind(callback
,
316 false, // return status
317 cryptohome::MOUNT_ERROR_FATAL
));
325 VLOG(1) << "Adding handler for " << async_id
;
326 DCHECK_EQ(callback_map_
.count(async_id
), 0U);
327 DCHECK_EQ(data_callback_map_
.count(async_id
), 0U);
328 callback_map_
[async_id
] = CallbackElement(callback
);
331 // Registers a callback which is called when the result for AsyncXXX is ready.
332 void RegisterAsyncDataCallback(
333 DataCallback callback
, const char* error
, int async_id
) {
334 if (async_id
== chromeos::CryptohomeClient::kNotReadyAsyncId
) {
335 base::MessageLoopProxy::current()->PostTask(
336 FROM_HERE
, base::Bind(callback
,
337 false, // return status
345 VLOG(1) << "Adding handler for " << async_id
;
346 DCHECK_EQ(callback_map_
.count(async_id
), 0U);
347 DCHECK_EQ(data_callback_map_
.count(async_id
), 0U);
348 data_callback_map_
[async_id
] = DataCallbackElement(callback
);
351 CallbackMap callback_map_
;
352 DataCallbackMap data_callback_map_
;
353 base::WeakPtrFactory
<AsyncMethodCallerImpl
> weak_ptr_factory_
;
355 DISALLOW_COPY_AND_ASSIGN(AsyncMethodCallerImpl
);
361 void AsyncMethodCaller::Initialize() {
362 if (g_async_method_caller
) {
363 LOG(WARNING
) << "AsyncMethodCaller was already initialized";
366 g_async_method_caller
= new AsyncMethodCallerImpl();
367 VLOG(1) << "AsyncMethodCaller initialized";
371 void AsyncMethodCaller::InitializeForTesting(
372 AsyncMethodCaller
* async_method_caller
) {
373 if (g_async_method_caller
) {
374 LOG(WARNING
) << "AsyncMethodCaller was already initialized";
377 g_async_method_caller
= async_method_caller
;
378 VLOG(1) << "AsyncMethodCaller initialized";
382 void AsyncMethodCaller::Shutdown() {
383 if (!g_async_method_caller
) {
384 LOG(WARNING
) << "AsyncMethodCaller::Shutdown() called with NULL manager";
387 delete g_async_method_caller
;
388 g_async_method_caller
= NULL
;
389 VLOG(1) << "AsyncMethodCaller Shutdown completed";
393 AsyncMethodCaller
* AsyncMethodCaller::GetInstance() {
394 return g_async_method_caller
;
397 } // namespace cryptohome