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:
AsyncMethodCallerImpl()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
~AsyncMethodCallerImpl()33 virtual ~AsyncMethodCallerImpl() {
34 DBusThreadManager::Get()->GetCryptohomeClient()->
35 ResetAsyncCallStatusHandlers();
36 }
37
AsyncCheckKey(const std::string & user_email,const std::string & passhash,Callback callback)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
AsyncMigrateKey(const std::string & user_email,const std::string & old_hash,const std::string & new_hash,Callback callback)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
AsyncMount(const std::string & user_email,const std::string & passhash,int flags,Callback callback)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
AsyncAddKey(const std::string & user_email,const std::string & passhash,const std::string & new_passhash,Callback callback)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
AsyncMountGuest(Callback callback)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
AsyncMountPublic(const std::string & public_mount_id,int flags,Callback callback)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
AsyncRemove(const std::string & user_email,Callback callback)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
AsyncTpmAttestationCreateEnrollRequest(const DataCallback & callback)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
AsyncTpmAttestationEnroll(const std::string & pca_response,const Callback & callback)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
AsyncTpmAttestationCreateCertRequest(chromeos::attestation::AttestationCertificateProfile certificate_profile,const std::string & user_id,const std::string & request_origin,const DataCallback & callback)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
AsyncTpmAttestationFinishCertRequest(const std::string & pca_response,chromeos::attestation::AttestationKeyType key_type,const std::string & user_id,const std::string & key_name,const DataCallback & callback)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
TpmAttestationRegisterKey(chromeos::attestation::AttestationKeyType key_type,const std::string & user_id,const std::string & key_name,const Callback & callback)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
TpmAttestationSignEnterpriseChallenge(chromeos::attestation::AttestationKeyType key_type,const std::string & user_id,const std::string & key_name,const std::string & domain,const std::string & device_id,chromeos::attestation::AttestationChallengeOptions options,const std::string & challenge,const DataCallback & callback)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
TpmAttestationSignSimpleChallenge(chromeos::attestation::AttestationKeyType key_type,const std::string & user_id,const std::string & key_name,const std::string & challenge,const DataCallback & callback)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
AsyncGetSanitizedUsername(const std::string & user,const DataCallback & callback)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
GetSanitizedUsernameCallback(const DataCallback & callback,const chromeos::DBusMethodCallStatus call_status,const std::string & result)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 {
CallbackElementcryptohome::__anonc41b8f810111::AsyncMethodCallerImpl::CallbackElement251 CallbackElement() {}
CallbackElementcryptohome::__anonc41b8f810111::AsyncMethodCallerImpl::CallbackElement252 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 {
DataCallbackElementcryptohome::__anonc41b8f810111::AsyncMethodCallerImpl::DataCallbackElement261 DataCallbackElement() {}
DataCallbackElementcryptohome::__anonc41b8f810111::AsyncMethodCallerImpl::DataCallbackElement262 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".
HandleAsyncResponse(int async_id,bool return_status,int return_code)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.
HandleAsyncDataResponse(int async_id,bool return_status,const std::string & return_data)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.
RegisterAsyncCallback(Callback callback,const char * error,int async_id)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.
RegisterAsyncDataCallback(DataCallback callback,const char * error,int async_id)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
Initialize()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
InitializeForTesting(AsyncMethodCaller * async_method_caller)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
Shutdown()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
GetInstance()378 AsyncMethodCaller* AsyncMethodCaller::GetInstance() {
379 return g_async_method_caller;
380 }
381
382 } // namespace cryptohome
383