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