Home | History | Annotate | Download | only in password_manager
      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 "chrome/browser/password_manager/password_store_win.h"
      6 
      7 #include <map>
      8 
      9 #include "base/bind.h"
     10 #include "base/logging.h"
     11 #include "base/memory/scoped_ptr.h"
     12 #include "base/strings/string_util.h"
     13 #include "base/strings/utf_string_conversions.h"
     14 #include "chrome/browser/password_manager/password_manager.h"
     15 #include "chrome/browser/profiles/profile.h"
     16 #include "chrome/browser/webdata/web_data_service.h"
     17 #include "components/webdata/encryptor/ie7_password.h"
     18 
     19 using content::BrowserThread;
     20 using content::PasswordForm;
     21 
     22 // Handles requests to WebDataService.
     23 class PasswordStoreWin::DBHandler : public WebDataServiceConsumer {
     24  public:
     25   DBHandler(WebDataService* web_data_service,
     26             PasswordStoreWin* password_store)
     27       : web_data_service_(web_data_service),
     28         password_store_(password_store) {
     29   }
     30 
     31   ~DBHandler();
     32 
     33   // Requests the IE7 login for |form|. This is async. |callback_runner| will be
     34   // run when complete.
     35   void GetIE7Login(
     36       const PasswordForm& form,
     37       const PasswordStoreWin::ConsumerCallbackRunner& callback_runner);
     38 
     39  private:
     40   struct RequestInfo {
     41     RequestInfo() {}
     42 
     43     RequestInfo(PasswordForm* request_form,
     44                 const PasswordStoreWin::ConsumerCallbackRunner& runner)
     45         : form(request_form),
     46           callback_runner(runner) {}
     47 
     48     PasswordForm* form;
     49     PasswordStoreWin::ConsumerCallbackRunner callback_runner;
     50   };
     51 
     52   // Holds info associated with in-flight GetIE7Login requests.
     53   typedef std::map<WebDataService::Handle, RequestInfo> PendingRequestMap;
     54 
     55   // Gets logins from IE7 if no others are found. Also copies them into
     56   // Chrome's WebDatabase so we don't need to look next time.
     57   PasswordForm* GetIE7Result(const WDTypedResult* result,
     58                              const PasswordForm& form);
     59 
     60   // WebDataServiceConsumer implementation.
     61   virtual void OnWebDataServiceRequestDone(
     62       WebDataService::Handle handle,
     63       const WDTypedResult* result) OVERRIDE;
     64 
     65   scoped_refptr<WebDataService> web_data_service_;
     66 
     67   // This creates a cycle between us and PasswordStore. The cycle is broken
     68   // from PasswordStoreWin::Shutdown, which deletes us.
     69   scoped_refptr<PasswordStoreWin> password_store_;
     70 
     71   PendingRequestMap pending_requests_;
     72 
     73   DISALLOW_COPY_AND_ASSIGN(DBHandler);
     74 };
     75 
     76 PasswordStoreWin::DBHandler::~DBHandler() {
     77   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
     78   for (PendingRequestMap::const_iterator i = pending_requests_.begin();
     79        i != pending_requests_.end();
     80        ++i) {
     81     web_data_service_->CancelRequest(i->first);
     82     delete i->second.form;
     83   }
     84 }
     85 
     86 void PasswordStoreWin::DBHandler::GetIE7Login(
     87     const PasswordForm& form,
     88     const PasswordStoreWin::ConsumerCallbackRunner& callback_runner) {
     89   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
     90   IE7PasswordInfo info;
     91   info.url_hash = ie7_password::GetUrlHash(UTF8ToWide(form.origin.spec()));
     92   WebDataService::Handle handle = web_data_service_->GetIE7Login(info, this);
     93   pending_requests_[handle] =
     94       RequestInfo(new PasswordForm(form), callback_runner);
     95 }
     96 
     97 PasswordForm* PasswordStoreWin::DBHandler::GetIE7Result(
     98     const WDTypedResult *result,
     99     const PasswordForm& form) {
    100   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
    101 
    102   const WDResult<IE7PasswordInfo>* r =
    103       static_cast<const WDResult<IE7PasswordInfo>*>(result);
    104   IE7PasswordInfo info = r->GetValue();
    105 
    106   if (!info.encrypted_data.empty()) {
    107     // We got a result.
    108     // Delete the entry. If it's good we will add it to the real saved password
    109     // table.
    110     web_data_service_->RemoveIE7Login(info);
    111     std::wstring username;
    112     std::wstring password;
    113     std::wstring url = ASCIIToWide(form.origin.spec());
    114     if (!ie7_password::DecryptPassword(url, info.encrypted_data,
    115                                        &username, &password)) {
    116       return NULL;
    117     }
    118 
    119     PasswordForm* autofill = new PasswordForm(form);
    120     autofill->username_value = username;
    121     autofill->password_value = password;
    122     autofill->preferred = true;
    123     autofill->ssl_valid = form.origin.SchemeIsSecure();
    124     autofill->date_created = info.date_created;
    125     // Add this PasswordForm to the saved password table. We're on the DB thread
    126     // already, so we use AddLoginImpl.
    127     password_store_->AddLoginImpl(*autofill);
    128     return autofill;
    129   }
    130   return NULL;
    131 }
    132 
    133 void PasswordStoreWin::DBHandler::OnWebDataServiceRequestDone(
    134     WebDataService::Handle handle,
    135     const WDTypedResult* result) {
    136   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
    137 
    138   PendingRequestMap::iterator i = pending_requests_.find(handle);
    139   DCHECK(i != pending_requests_.end());
    140 
    141   scoped_ptr<PasswordForm> form(i->second.form);
    142   PasswordStoreWin::ConsumerCallbackRunner callback_runner(
    143       i->second.callback_runner);
    144   pending_requests_.erase(i);
    145 
    146   std::vector<content::PasswordForm*> matched_forms;
    147 
    148   if (!result) {
    149     // The WDS returns NULL if it is shutting down. Run callback with empty
    150     // result.
    151     callback_runner.Run(matched_forms);
    152     return;
    153   }
    154 
    155   DCHECK_EQ(PASSWORD_IE7_RESULT, result->GetType());
    156   PasswordForm* ie7_form = GetIE7Result(result, *form);
    157 
    158   if (ie7_form)
    159     matched_forms.push_back(ie7_form);
    160 
    161   callback_runner.Run(matched_forms);
    162 }
    163 
    164 PasswordStoreWin::PasswordStoreWin(LoginDatabase* login_database,
    165                                    Profile* profile,
    166                                    WebDataService* web_data_service)
    167     : PasswordStoreDefault(login_database, profile) {
    168   db_handler_.reset(new DBHandler(web_data_service, this));
    169 }
    170 
    171 PasswordStoreWin::~PasswordStoreWin() {
    172 }
    173 
    174 void PasswordStoreWin::ShutdownOnDBThread() {
    175   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
    176   db_handler_.reset();
    177 }
    178 
    179 void PasswordStoreWin::ShutdownOnUIThread() {
    180   BrowserThread::PostTask(
    181       BrowserThread::DB, FROM_HERE,
    182       base::Bind(&PasswordStoreWin::ShutdownOnDBThread, this));
    183   PasswordStoreDefault::ShutdownOnUIThread();
    184 }
    185 
    186 void PasswordStoreWin::GetIE7LoginIfNecessary(
    187     const PasswordForm& form,
    188     const ConsumerCallbackRunner& callback_runner,
    189     const std::vector<content::PasswordForm*>& matched_forms) {
    190   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
    191   if (matched_forms.empty() && db_handler_.get()) {
    192     db_handler_->GetIE7Login(form, callback_runner);
    193   } else {
    194     // No need to get IE7 login.
    195     callback_runner.Run(matched_forms);
    196   }
    197 }
    198 
    199 void PasswordStoreWin::GetLoginsImpl(
    200     const PasswordForm& form,
    201     const ConsumerCallbackRunner& callback_runner) {
    202   ConsumerCallbackRunner get_ie7_login =
    203       base::Bind(&PasswordStoreWin::GetIE7LoginIfNecessary,
    204                  this, form, callback_runner);
    205   PasswordStoreDefault::GetLoginsImpl(form, get_ie7_login);
    206 }
    207