password_store_win.cc revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
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/string_util.h"
13#include "base/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
19using content::BrowserThread;
20using content::PasswordForm;
21
22// Handles requests to WebDataService.
23class 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
76PasswordStoreWin::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
86void 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
97PasswordForm* 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
133void 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
164PasswordStoreWin::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
171PasswordStoreWin::~PasswordStoreWin() {
172}
173
174void PasswordStoreWin::ShutdownOnDBThread() {
175  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
176  db_handler_.reset();
177}
178
179void PasswordStoreWin::ShutdownOnUIThread() {
180  BrowserThread::PostTask(
181      BrowserThread::DB, FROM_HERE,
182      base::Bind(&PasswordStoreWin::ShutdownOnDBThread, this));
183  PasswordStoreDefault::ShutdownOnUIThread();
184}
185
186void 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
199void 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