• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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