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