• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 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 "components/password_manager/core/browser/password_store.h"
6 
7 #include "base/bind.h"
8 #include "base/debug/dump_without_crashing.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/message_loop/message_loop_proxy.h"
12 #include "base/metrics/histogram.h"
13 #include "base/stl_util.h"
14 #include "components/autofill/core/common/password_form.h"
15 #include "components/password_manager/core/browser/password_store_consumer.h"
16 #include "components/password_manager/core/browser/password_syncable_service.h"
17 
18 #if defined(PASSWORD_MANAGER_ENABLE_SYNC)
19 #include "components/password_manager/core/browser/password_syncable_service.h"
20 #endif
21 
22 using autofill::PasswordForm;
23 
24 namespace password_manager {
25 
26 namespace {
27 
28 // Calls |consumer| back with the request result, if |consumer| is still alive.
29 // Takes ownership of the elements in |result|, passing ownership to |consumer|
30 // if it is still alive.
MaybeCallConsumerCallback(base::WeakPtr<PasswordStoreConsumer> consumer,scoped_ptr<std::vector<PasswordForm * >> result)31 void MaybeCallConsumerCallback(base::WeakPtr<PasswordStoreConsumer> consumer,
32                                scoped_ptr<std::vector<PasswordForm*> > result) {
33   if (consumer.get())
34     consumer->OnGetPasswordStoreResults(*result);
35   else
36     STLDeleteElements(result.get());
37 }
38 
39 // http://crbug.com/404012. Let's see where the empty fields come from.
CheckForEmptyUsernameAndPassword(const PasswordForm & form)40 void CheckForEmptyUsernameAndPassword(const PasswordForm& form) {
41   if (form.username_value.empty() &&
42       form.password_value.empty() &&
43       !form.blacklisted_by_user)
44     base::debug::DumpWithoutCrashing();
45 }
46 
47 }  // namespace
48 
GetLoginsRequest(PasswordStoreConsumer * consumer)49 PasswordStore::GetLoginsRequest::GetLoginsRequest(
50     PasswordStoreConsumer* consumer)
51     : consumer_weak_(consumer->GetWeakPtr()),
52       result_(new std::vector<PasswordForm*>()) {
53   DCHECK(thread_checker_.CalledOnValidThread());
54   origin_loop_ = base::MessageLoopProxy::current();
55 }
56 
~GetLoginsRequest()57 PasswordStore::GetLoginsRequest::~GetLoginsRequest() {
58 }
59 
ApplyIgnoreLoginsCutoff()60 void PasswordStore::GetLoginsRequest::ApplyIgnoreLoginsCutoff() {
61   if (!ignore_logins_cutoff_.is_null()) {
62     // Count down rather than up since we may be deleting elements.
63     // Note that in principle it could be more efficient to copy the whole array
64     // since that's worst-case linear time, but we expect that elements will be
65     // deleted rarely and lists will be small, so this avoids the copies.
66     for (size_t i = result_->size(); i > 0; --i) {
67       if ((*result_)[i - 1]->date_created < ignore_logins_cutoff_) {
68         delete (*result_)[i - 1];
69         result_->erase(result_->begin() + (i - 1));
70       }
71     }
72   }
73 }
74 
ForwardResult()75 void PasswordStore::GetLoginsRequest::ForwardResult() {
76   origin_loop_->PostTask(FROM_HERE,
77                          base::Bind(&MaybeCallConsumerCallback,
78                                     consumer_weak_,
79                                     base::Passed(result_.Pass())));
80 }
81 
PasswordStore(scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner,scoped_refptr<base::SingleThreadTaskRunner> db_thread_runner)82 PasswordStore::PasswordStore(
83     scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner,
84     scoped_refptr<base::SingleThreadTaskRunner> db_thread_runner)
85     : main_thread_runner_(main_thread_runner),
86       db_thread_runner_(db_thread_runner),
87       observers_(new ObserverListThreadSafe<Observer>()),
88       shutdown_called_(false) {}
89 
Init(const syncer::SyncableService::StartSyncFlare & flare,const std::string & sync_username)90 bool PasswordStore::Init(const syncer::SyncableService::StartSyncFlare& flare,
91                          const std::string& sync_username) {
92   ReportMetrics(sync_username);
93 #if defined(PASSWORD_MANAGER_ENABLE_SYNC)
94   ScheduleTask(base::Bind(&PasswordStore::InitSyncableService, this, flare));
95 #endif
96   return true;
97 }
98 
AddLogin(const PasswordForm & form)99 void PasswordStore::AddLogin(const PasswordForm& form) {
100   CheckForEmptyUsernameAndPassword(form);
101   ScheduleTask(
102       base::Bind(&PasswordStore::WrapModificationTask, this,
103                  base::Bind(&PasswordStore::AddLoginImpl, this, form)));
104 }
105 
UpdateLogin(const PasswordForm & form)106 void PasswordStore::UpdateLogin(const PasswordForm& form) {
107   CheckForEmptyUsernameAndPassword(form);
108   ScheduleTask(
109       base::Bind(&PasswordStore::WrapModificationTask, this,
110                  base::Bind(&PasswordStore::UpdateLoginImpl, this, form)));
111 }
112 
RemoveLogin(const PasswordForm & form)113 void PasswordStore::RemoveLogin(const PasswordForm& form) {
114   ScheduleTask(
115       base::Bind(&PasswordStore::WrapModificationTask, this,
116                  base::Bind(&PasswordStore::RemoveLoginImpl, this, form)));
117 }
118 
RemoveLoginsCreatedBetween(base::Time delete_begin,base::Time delete_end)119 void PasswordStore::RemoveLoginsCreatedBetween(base::Time delete_begin,
120                                                base::Time delete_end) {
121   ScheduleTask(
122       base::Bind(&PasswordStore::WrapModificationTask, this,
123                  base::Bind(&PasswordStore::RemoveLoginsCreatedBetweenImpl,
124                             this, delete_begin, delete_end)));
125 }
126 
RemoveLoginsSyncedBetween(base::Time delete_begin,base::Time delete_end)127 void PasswordStore::RemoveLoginsSyncedBetween(base::Time delete_begin,
128                                               base::Time delete_end) {
129   ScheduleTask(
130       base::Bind(&PasswordStore::WrapModificationTask,
131                  this,
132                  base::Bind(&PasswordStore::RemoveLoginsSyncedBetweenImpl,
133                             this,
134                             delete_begin,
135                             delete_end)));
136 }
137 
GetLogins(const PasswordForm & form,AuthorizationPromptPolicy prompt_policy,PasswordStoreConsumer * consumer)138 void PasswordStore::GetLogins(
139     const PasswordForm& form,
140     AuthorizationPromptPolicy prompt_policy,
141     PasswordStoreConsumer* consumer) {
142   // Per http://crbug.com/121738, we deliberately ignore saved logins for
143   // http*://www.google.com/ that were stored prior to 2012. (Google now uses
144   // https://accounts.google.com/ for all login forms, so these should be
145   // unused.) We don't delete them just yet, and they'll still be visible in the
146   // password manager, but we won't use them to autofill any forms. This is a
147   // security feature to help minimize damage that can be done by XSS attacks.
148   // TODO(mdm): actually delete them at some point, say M24 or so.
149   base::Time ignore_logins_cutoff;  // the null time
150   if (form.scheme == PasswordForm::SCHEME_HTML &&
151       (form.signon_realm == "http://www.google.com" ||
152        form.signon_realm == "http://www.google.com/" ||
153        form.signon_realm == "https://www.google.com" ||
154        form.signon_realm == "https://www.google.com/")) {
155     static const base::Time::Exploded exploded_cutoff =
156         { 2012, 1, 0, 1, 0, 0, 0, 0 };  // 00:00 Jan 1 2012
157     ignore_logins_cutoff = base::Time::FromUTCExploded(exploded_cutoff);
158   }
159   GetLoginsRequest* request = new GetLoginsRequest(consumer);
160   request->set_ignore_logins_cutoff(ignore_logins_cutoff);
161 
162   ConsumerCallbackRunner callback_runner =
163       base::Bind(&PasswordStore::CopyAndForwardLoginsResult,
164                  this, base::Owned(request));
165   ScheduleTask(base::Bind(&PasswordStore::GetLoginsImpl,
166                           this, form, prompt_policy, callback_runner));
167 }
168 
GetAutofillableLogins(PasswordStoreConsumer * consumer)169 void PasswordStore::GetAutofillableLogins(PasswordStoreConsumer* consumer) {
170   Schedule(&PasswordStore::GetAutofillableLoginsImpl, consumer);
171 }
172 
GetBlacklistLogins(PasswordStoreConsumer * consumer)173 void PasswordStore::GetBlacklistLogins(PasswordStoreConsumer* consumer) {
174   Schedule(&PasswordStore::GetBlacklistLoginsImpl, consumer);
175 }
176 
ReportMetrics(const std::string & sync_username)177 void PasswordStore::ReportMetrics(const std::string& sync_username) {
178   ScheduleTask(base::Bind(&PasswordStore::ReportMetricsImpl, this,
179                           sync_username));
180 }
181 
AddObserver(Observer * observer)182 void PasswordStore::AddObserver(Observer* observer) {
183   observers_->AddObserver(observer);
184 }
185 
RemoveObserver(Observer * observer)186 void PasswordStore::RemoveObserver(Observer* observer) {
187   observers_->RemoveObserver(observer);
188 }
189 
ScheduleTask(const base::Closure & task)190 bool PasswordStore::ScheduleTask(const base::Closure& task) {
191   scoped_refptr<base::SingleThreadTaskRunner> task_runner(
192       GetBackgroundTaskRunner());
193   if (task_runner.get())
194     return task_runner->PostTask(FROM_HERE, task);
195   return false;
196 }
197 
Shutdown()198 void PasswordStore::Shutdown() {
199 #if defined(PASSWORD_MANAGER_ENABLE_SYNC)
200   ScheduleTask(base::Bind(&PasswordStore::DestroySyncableService, this));
201 #endif
202   shutdown_called_ = true;
203 }
204 
205 #if defined(PASSWORD_MANAGER_ENABLE_SYNC)
206 base::WeakPtr<syncer::SyncableService>
GetPasswordSyncableService()207     PasswordStore::GetPasswordSyncableService() {
208   DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
209   DCHECK(syncable_service_);
210   return syncable_service_->AsWeakPtr();
211 }
212 #endif
213 
~PasswordStore()214 PasswordStore::~PasswordStore() { DCHECK(shutdown_called_); }
215 
216 scoped_refptr<base::SingleThreadTaskRunner>
GetBackgroundTaskRunner()217 PasswordStore::GetBackgroundTaskRunner() {
218   return db_thread_runner_;
219 }
220 
ForwardLoginsResult(GetLoginsRequest * request)221 void PasswordStore::ForwardLoginsResult(GetLoginsRequest* request) {
222   request->ApplyIgnoreLoginsCutoff();
223   request->ForwardResult();
224 }
225 
CopyAndForwardLoginsResult(PasswordStore::GetLoginsRequest * request,const std::vector<PasswordForm * > & matched_forms)226 void PasswordStore::CopyAndForwardLoginsResult(
227     PasswordStore::GetLoginsRequest* request,
228     const std::vector<PasswordForm*>& matched_forms) {
229   // Copy the contents of |matched_forms| into the request. The request takes
230   // ownership of the PasswordForm elements.
231   *(request->result()) = matched_forms;
232   ForwardLoginsResult(request);
233 }
234 
LogStatsForBulkDeletion(int num_deletions)235 void PasswordStore::LogStatsForBulkDeletion(int num_deletions) {
236   UMA_HISTOGRAM_COUNTS("PasswordManager.NumPasswordsDeletedByBulkDelete",
237                        num_deletions);
238 }
239 
NotifyLoginsChanged(const PasswordStoreChangeList & changes)240 void PasswordStore::NotifyLoginsChanged(
241     const PasswordStoreChangeList& changes) {
242   DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
243   if (!changes.empty()) {
244     observers_->Notify(&Observer::OnLoginsChanged, changes);
245 #if defined(PASSWORD_MANAGER_ENABLE_SYNC)
246     if (syncable_service_)
247       syncable_service_->ActOnPasswordStoreChanges(changes);
248 #endif
249   }
250 }
251 
252 template<typename BackendFunc>
Schedule(BackendFunc func,PasswordStoreConsumer * consumer)253 void PasswordStore::Schedule(
254     BackendFunc func,
255     PasswordStoreConsumer* consumer) {
256   GetLoginsRequest* request = new GetLoginsRequest(consumer);
257   consumer->cancelable_task_tracker()->PostTask(
258       GetBackgroundTaskRunner().get(),
259       FROM_HERE,
260       base::Bind(func, this, base::Owned(request)));
261 }
262 
WrapModificationTask(ModificationTask task)263 void PasswordStore::WrapModificationTask(ModificationTask task) {
264   PasswordStoreChangeList changes = task.Run();
265   NotifyLoginsChanged(changes);
266 }
267 
268 #if defined(PASSWORD_MANAGER_ENABLE_SYNC)
InitSyncableService(const syncer::SyncableService::StartSyncFlare & flare)269 void PasswordStore::InitSyncableService(
270     const syncer::SyncableService::StartSyncFlare& flare) {
271   DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
272   DCHECK(!syncable_service_);
273   syncable_service_.reset(new PasswordSyncableService(this));
274   syncable_service_->InjectStartSyncFlare(flare);
275 }
276 
DestroySyncableService()277 void PasswordStore::DestroySyncableService() {
278   DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
279   syncable_service_.reset();
280 }
281 #endif
282 
283 }  // namespace password_manager
284