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