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       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 
    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 
    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 
    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 
    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 
    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 
    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 {
    251     CallbackElement() {}
    252     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 {
    261     DataCallbackElement() {}
    262     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".
    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.
    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.
    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.
    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
    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
    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
    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
    378 AsyncMethodCaller* AsyncMethodCaller::GetInstance() {
    379   return g_async_method_caller;
    380 }
    381 
    382 }  // namespace cryptohome
    383