password_store_win.cc revision 4e180b6a0b4720a9b8e9e959a882386f690f08ff
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_win.h" 18 19using autofill::PasswordForm; 20using content::BrowserThread; 21 22// Handles requests to WebDataService. 23class 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 std::vector<autofill::PasswordForm*> GetIE7Results( 58 const WDTypedResult* result, 59 const PasswordForm& form); 60 61 // WebDataServiceConsumer implementation. 62 virtual void OnWebDataServiceRequestDone( 63 WebDataService::Handle handle, 64 const WDTypedResult* result) OVERRIDE; 65 66 scoped_refptr<WebDataService> web_data_service_; 67 68 // This creates a cycle between us and PasswordStore. The cycle is broken 69 // from PasswordStoreWin::Shutdown, which deletes us. 70 scoped_refptr<PasswordStoreWin> password_store_; 71 72 PendingRequestMap pending_requests_; 73 74 DISALLOW_COPY_AND_ASSIGN(DBHandler); 75}; 76 77PasswordStoreWin::DBHandler::~DBHandler() { 78 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); 79 for (PendingRequestMap::const_iterator i = pending_requests_.begin(); 80 i != pending_requests_.end(); 81 ++i) { 82 web_data_service_->CancelRequest(i->first); 83 delete i->second.form; 84 } 85} 86 87void PasswordStoreWin::DBHandler::GetIE7Login( 88 const PasswordForm& form, 89 const PasswordStoreWin::ConsumerCallbackRunner& callback_runner) { 90 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); 91 IE7PasswordInfo info; 92 info.url_hash = ie7_password::GetUrlHash(UTF8ToWide(form.origin.spec())); 93 WebDataService::Handle handle = web_data_service_->GetIE7Login(info, this); 94 pending_requests_[handle] = 95 RequestInfo(new PasswordForm(form), callback_runner); 96} 97 98std::vector<PasswordForm*> PasswordStoreWin::DBHandler::GetIE7Results( 99 const WDTypedResult *result, 100 const PasswordForm& form) { 101 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); 102 std::vector<PasswordForm*> matching_forms; 103 104 const WDResult<IE7PasswordInfo>* r = 105 static_cast<const WDResult<IE7PasswordInfo>*>(result); 106 IE7PasswordInfo info = r->GetValue(); 107 108 if (!info.encrypted_data.empty()) { 109 // We got a result. 110 // Delete the entry. If it's good we will add it to the real saved password 111 // table. 112 web_data_service_->RemoveIE7Login(info); 113 std::vector<ie7_password::DecryptedCredentials> credentials; 114 std::wstring url = ASCIIToWide(form.origin.spec()); 115 if (ie7_password::DecryptPasswords(url, 116 info.encrypted_data, 117 &credentials)) { 118 for (size_t i = 0; i < credentials.size(); ++i) { 119 PasswordForm* autofill = new PasswordForm(form); 120 autofill->username_value = credentials[i].username; 121 autofill->password_value = credentials[i].password; 122 autofill->preferred = true; 123 autofill->ssl_valid = form.origin.SchemeIsSecure(); 124 autofill->date_created = info.date_created; 125 matching_forms.push_back(autofill); 126 // Add this PasswordForm to the saved password table. We're on the DB 127 // thread already, so we use AddLoginImpl. 128 password_store_->AddLoginImpl(*autofill); 129 } 130 } 131 } 132 return matching_forms; 133} 134 135void PasswordStoreWin::DBHandler::OnWebDataServiceRequestDone( 136 WebDataService::Handle handle, 137 const WDTypedResult* result) { 138 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); 139 140 PendingRequestMap::iterator i = pending_requests_.find(handle); 141 DCHECK(i != pending_requests_.end()); 142 143 scoped_ptr<PasswordForm> form(i->second.form); 144 PasswordStoreWin::ConsumerCallbackRunner callback_runner( 145 i->second.callback_runner); 146 pending_requests_.erase(i); 147 148 if (!result) { 149 // The WDS returns NULL if it is shutting down. Run callback with empty 150 // result. 151 callback_runner.Run(std::vector<autofill::PasswordForm*>()); 152 return; 153 } 154 155 DCHECK_EQ(PASSWORD_IE7_RESULT, result->GetType()); 156 std::vector<autofill::PasswordForm*> matched_forms = 157 GetIE7Results(result, *form); 158 159 callback_runner.Run(matched_forms); 160} 161 162PasswordStoreWin::PasswordStoreWin(LoginDatabase* login_database, 163 Profile* profile, 164 WebDataService* web_data_service) 165 : PasswordStoreDefault(login_database, profile) { 166 db_handler_.reset(new DBHandler(web_data_service, this)); 167} 168 169PasswordStoreWin::~PasswordStoreWin() { 170} 171 172void PasswordStoreWin::ShutdownOnDBThread() { 173 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); 174 db_handler_.reset(); 175} 176 177void PasswordStoreWin::ShutdownOnUIThread() { 178 BrowserThread::PostTask( 179 BrowserThread::DB, FROM_HERE, 180 base::Bind(&PasswordStoreWin::ShutdownOnDBThread, this)); 181 PasswordStoreDefault::ShutdownOnUIThread(); 182} 183 184void PasswordStoreWin::GetIE7LoginIfNecessary( 185 const PasswordForm& form, 186 const ConsumerCallbackRunner& callback_runner, 187 const std::vector<autofill::PasswordForm*>& matched_forms) { 188 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); 189 if (matched_forms.empty() && db_handler_.get()) { 190 db_handler_->GetIE7Login(form, callback_runner); 191 } else { 192 // No need to get IE7 login. 193 callback_runner.Run(matched_forms); 194 } 195} 196 197void PasswordStoreWin::GetLoginsImpl( 198 const PasswordForm& form, 199 const ConsumerCallbackRunner& callback_runner) { 200 ConsumerCallbackRunner get_ie7_login = 201 base::Bind(&PasswordStoreWin::GetIE7LoginIfNecessary, 202 this, form, callback_runner); 203 PasswordStoreDefault::GetLoginsImpl(form, get_ie7_login); 204} 205