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. 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. 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 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 57 PasswordStore::GetLoginsRequest::~GetLoginsRequest() { 58 } 59 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 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 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 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 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 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 113 void PasswordStore::RemoveLogin(const PasswordForm& form) { 114 ScheduleTask( 115 base::Bind(&PasswordStore::WrapModificationTask, this, 116 base::Bind(&PasswordStore::RemoveLoginImpl, this, form))); 117 } 118 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 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 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 169 void PasswordStore::GetAutofillableLogins(PasswordStoreConsumer* consumer) { 170 Schedule(&PasswordStore::GetAutofillableLoginsImpl, consumer); 171 } 172 173 void PasswordStore::GetBlacklistLogins(PasswordStoreConsumer* consumer) { 174 Schedule(&PasswordStore::GetBlacklistLoginsImpl, consumer); 175 } 176 177 void PasswordStore::ReportMetrics(const std::string& sync_username) { 178 ScheduleTask(base::Bind(&PasswordStore::ReportMetricsImpl, this, 179 sync_username)); 180 } 181 182 void PasswordStore::AddObserver(Observer* observer) { 183 observers_->AddObserver(observer); 184 } 185 186 void PasswordStore::RemoveObserver(Observer* observer) { 187 observers_->RemoveObserver(observer); 188 } 189 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 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> 207 PasswordStore::GetPasswordSyncableService() { 208 DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread()); 209 DCHECK(syncable_service_); 210 return syncable_service_->AsWeakPtr(); 211 } 212 #endif 213 214 PasswordStore::~PasswordStore() { DCHECK(shutdown_called_); } 215 216 scoped_refptr<base::SingleThreadTaskRunner> 217 PasswordStore::GetBackgroundTaskRunner() { 218 return db_thread_runner_; 219 } 220 221 void PasswordStore::ForwardLoginsResult(GetLoginsRequest* request) { 222 request->ApplyIgnoreLoginsCutoff(); 223 request->ForwardResult(); 224 } 225 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 235 void PasswordStore::LogStatsForBulkDeletion(int num_deletions) { 236 UMA_HISTOGRAM_COUNTS("PasswordManager.NumPasswordsDeletedByBulkDelete", 237 num_deletions); 238 } 239 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> 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 263 void PasswordStore::WrapModificationTask(ModificationTask task) { 264 PasswordStoreChangeList changes = task.Run(); 265 NotifyLoginsChanged(changes); 266 } 267 268 #if defined(PASSWORD_MANAGER_ENABLE_SYNC) 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 277 void PasswordStore::DestroySyncableService() { 278 DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread()); 279 syncable_service_.reset(); 280 } 281 #endif 282 283 } // namespace password_manager 284