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:
FormGetLoginsRequest(PasswordStore::GetLoginsCallback * callback)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.
SetLoginsRequestForm(const PasswordForm & form)31 void SetLoginsRequestForm(const PasswordForm& form) {
32 form_.reset(new PasswordForm(form));
33 }
form() const34 PasswordForm* form() const {
35 return form_.get();
36 }
IsLoginsRequest() const37 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:
DBHandler(WebDataService * web_data_service,PasswordStoreWin * password_store)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
~DBHandler()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
GetIE7Login(const GURL & url,GetLoginsRequest * request)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
GetIE7Result(const WDTypedResult * result,const PasswordForm & form)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
OnWebDataServiceRequestDone(WebDataService::Handle handle,const WDTypedResult * result)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
PasswordStoreWin(LoginDatabase * login_database,Profile * profile,WebDataService * web_data_service)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
~PasswordStoreWin()173 PasswordStoreWin::~PasswordStoreWin() {
174 }
175
ShutdownOnDBThread()176 void PasswordStoreWin::ShutdownOnDBThread() {
177 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
178 db_handler_.reset();
179 }
180
NewGetLoginsRequest(GetLoginsCallback * callback)181 PasswordStore::GetLoginsRequest* PasswordStoreWin::NewGetLoginsRequest(
182 GetLoginsCallback* callback) {
183 return new FormGetLoginsRequest(callback);
184 }
185
Shutdown()186 void PasswordStoreWin::Shutdown() {
187 BrowserThread::PostTask(
188 BrowserThread::DB, FROM_HERE,
189 NewRunnableMethod(this, &PasswordStoreWin::ShutdownOnDBThread));
190 PasswordStoreDefault::Shutdown();
191 }
192
ForwardLoginsResult(GetLoginsRequest * request)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
GetLoginsImpl(GetLoginsRequest * request,const PasswordForm & form)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