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(chromeos::attestation::PrivacyCAType pca_type,const DataCallback & callback)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
AsyncTpmAttestationEnroll(chromeos::attestation::PrivacyCAType pca_type,const std::string & pca_response,const Callback & callback)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
AsyncTpmAttestationCreateCertRequest(chromeos::attestation::PrivacyCAType pca_type,chromeos::attestation::AttestationCertificateProfile certificate_profile,const std::string & user_id,const std::string & request_origin,const DataCallback & callback)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
AsyncTpmAttestationFinishCertRequest(const std::string & pca_response,chromeos::attestation::AttestationKeyType key_type,const std::string & user_id,const std::string & key_name,const DataCallback & callback)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
TpmAttestationRegisterKey(chromeos::attestation::AttestationKeyType key_type,const std::string & user_id,const std::string & key_name,const Callback & callback)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
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)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
TpmAttestationSignSimpleChallenge(chromeos::attestation::AttestationKeyType key_type,const std::string & user_id,const std::string & key_name,const std::string & challenge,const DataCallback & callback)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
AsyncGetSanitizedUsername(const std::string & user,const DataCallback & callback)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
GetSanitizedUsernameCallback(const DataCallback & callback,const chromeos::DBusMethodCallStatus call_status,const std::string & result)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 {
CallbackElementcryptohome::__anonab3e8a0e0111::AsyncMethodCallerImpl::CallbackElement256 CallbackElement() {}
CallbackElementcryptohome::__anonab3e8a0e0111::AsyncMethodCallerImpl::CallbackElement257 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 {
DataCallbackElementcryptohome::__anonab3e8a0e0111::AsyncMethodCallerImpl::DataCallbackElement266 DataCallbackElement() {}
DataCallbackElementcryptohome::__anonab3e8a0e0111::AsyncMethodCallerImpl::DataCallbackElement267 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".
HandleAsyncResponse(int async_id,bool return_status,int return_code)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.
HandleAsyncDataResponse(int async_id,bool return_status,const std::string & return_data)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.
RegisterAsyncCallback(Callback callback,const char * error,int async_id)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.
RegisterAsyncDataCallback(DataCallback callback,const char * error,int async_id)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
Initialize()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
InitializeForTesting(AsyncMethodCaller * async_method_caller)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
Shutdown()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
GetInstance()383 AsyncMethodCaller* AsyncMethodCaller::GetInstance() {
384 return g_async_method_caller;
385 }
386
387 } // namespace cryptohome
388