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