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