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