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