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       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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 {
    256     CallbackElement() {}
    257     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 {
    266     DataCallbackElement() {}
    267     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".
    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.
    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.
    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.
    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
    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
    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
    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
    383 AsyncMethodCaller* AsyncMethodCaller::GetInstance() {
    384   return g_async_method_caller;
    385 }
    386 
    387 }  // namespace cryptohome
    388