• 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_x.h"
6 
7 #include <map>
8 #include <vector>
9 
10 #include "base/logging.h"
11 #include "base/stl_util-inl.h"
12 #include "chrome/browser/password_manager/password_store_change.h"
13 #include "content/browser/browser_thread.h"
14 #include "content/common/notification_service.h"
15 
16 using std::vector;
17 using webkit_glue::PasswordForm;
18 
PasswordStoreX(LoginDatabase * login_db,Profile * profile,WebDataService * web_data_service,NativeBackend * backend)19 PasswordStoreX::PasswordStoreX(LoginDatabase* login_db,
20                                Profile* profile,
21                                WebDataService* web_data_service,
22                                NativeBackend* backend)
23     : PasswordStoreDefault(login_db, profile, web_data_service),
24       backend_(backend), migration_checked_(!backend), allow_fallback_(false) {
25 }
26 
~PasswordStoreX()27 PasswordStoreX::~PasswordStoreX() {
28 }
29 
AddLoginImpl(const PasswordForm & form)30 void PasswordStoreX::AddLoginImpl(const PasswordForm& form) {
31   CheckMigration();
32   if (use_native_backend() && backend_->AddLogin(form)) {
33     PasswordStoreChangeList changes;
34     changes.push_back(PasswordStoreChange(PasswordStoreChange::ADD, form));
35     NotificationService::current()->Notify(
36         NotificationType::LOGINS_CHANGED,
37         Source<PasswordStore>(this),
38         Details<PasswordStoreChangeList>(&changes));
39     allow_fallback_ = false;
40   } else if (allow_default_store()) {
41     PasswordStoreDefault::AddLoginImpl(form);
42   }
43 }
44 
UpdateLoginImpl(const PasswordForm & form)45 void PasswordStoreX::UpdateLoginImpl(const PasswordForm& form) {
46   CheckMigration();
47   if (use_native_backend() && backend_->UpdateLogin(form)) {
48     PasswordStoreChangeList changes;
49     changes.push_back(PasswordStoreChange(PasswordStoreChange::UPDATE, form));
50     NotificationService::current()->Notify(
51         NotificationType::LOGINS_CHANGED,
52         Source<PasswordStore>(this),
53         Details<PasswordStoreChangeList>(&changes));
54     allow_fallback_ = false;
55   } else if (allow_default_store()) {
56     PasswordStoreDefault::UpdateLoginImpl(form);
57   }
58 }
59 
RemoveLoginImpl(const PasswordForm & form)60 void PasswordStoreX::RemoveLoginImpl(const PasswordForm& form) {
61   CheckMigration();
62   if (use_native_backend() && backend_->RemoveLogin(form)) {
63     PasswordStoreChangeList changes;
64     changes.push_back(PasswordStoreChange(PasswordStoreChange::REMOVE, form));
65     NotificationService::current()->Notify(
66         NotificationType::LOGINS_CHANGED,
67         Source<PasswordStore>(this),
68         Details<PasswordStoreChangeList>(&changes));
69     allow_fallback_ = false;
70   } else if (allow_default_store()) {
71     PasswordStoreDefault::RemoveLoginImpl(form);
72   }
73 }
74 
RemoveLoginsCreatedBetweenImpl(const base::Time & delete_begin,const base::Time & delete_end)75 void PasswordStoreX::RemoveLoginsCreatedBetweenImpl(
76     const base::Time& delete_begin,
77     const base::Time& delete_end) {
78   CheckMigration();
79   vector<PasswordForm*> forms;
80   if (use_native_backend() &&
81       backend_->GetLoginsCreatedBetween(delete_begin, delete_end, &forms) &&
82       backend_->RemoveLoginsCreatedBetween(delete_begin, delete_end)) {
83     PasswordStoreChangeList changes;
84     for (vector<PasswordForm*>::const_iterator it = forms.begin();
85          it != forms.end(); ++it) {
86       changes.push_back(PasswordStoreChange(PasswordStoreChange::REMOVE,
87                                             **it));
88     }
89     NotificationService::current()->Notify(
90         NotificationType::LOGINS_CHANGED,
91         Source<PasswordStore>(this),
92         Details<PasswordStoreChangeList>(&changes));
93     allow_fallback_ = false;
94   } else if (allow_default_store()) {
95     PasswordStoreDefault::RemoveLoginsCreatedBetweenImpl(delete_begin,
96                                                          delete_end);
97   }
98   STLDeleteElements(&forms);
99 }
100 
GetLoginsImpl(GetLoginsRequest * request,const PasswordForm & form)101 void PasswordStoreX::GetLoginsImpl(GetLoginsRequest* request,
102                                    const PasswordForm& form) {
103   CheckMigration();
104   if (use_native_backend() && backend_->GetLogins(form, &request->value)) {
105     ForwardLoginsResult(request);
106     allow_fallback_ = false;
107   } else if (allow_default_store()) {
108     PasswordStoreDefault::GetLoginsImpl(request, form);
109   } else {
110     // The consumer will be left hanging unless we reply.
111     ForwardLoginsResult(request);
112   }
113 }
114 
GetAutofillableLoginsImpl(GetLoginsRequest * request)115 void PasswordStoreX::GetAutofillableLoginsImpl(GetLoginsRequest* request) {
116   CheckMigration();
117   if (use_native_backend() &&
118       backend_->GetAutofillableLogins(&request->value)) {
119     ForwardLoginsResult(request);
120     allow_fallback_ = false;
121   } else if (allow_default_store()) {
122     PasswordStoreDefault::GetAutofillableLoginsImpl(request);
123   } else {
124     // The consumer will be left hanging unless we reply.
125     ForwardLoginsResult(request);
126   }
127 }
128 
GetBlacklistLoginsImpl(GetLoginsRequest * request)129 void PasswordStoreX::GetBlacklistLoginsImpl(GetLoginsRequest* request) {
130   CheckMigration();
131   if (use_native_backend() &&
132       backend_->GetBlacklistLogins(&request->value)) {
133     ForwardLoginsResult(request);
134     allow_fallback_ = false;
135   } else if (allow_default_store()) {
136     PasswordStoreDefault::GetBlacklistLoginsImpl(request);
137   } else {
138     // The consumer will be left hanging unless we reply.
139     ForwardLoginsResult(request);
140   }
141 }
142 
FillAutofillableLogins(vector<PasswordForm * > * forms)143 bool PasswordStoreX::FillAutofillableLogins(vector<PasswordForm*>* forms) {
144   CheckMigration();
145   if (use_native_backend() && backend_->GetAutofillableLogins(forms)) {
146     allow_fallback_ = false;
147     return true;
148   }
149   if (allow_default_store())
150     return PasswordStoreDefault::FillAutofillableLogins(forms);
151   return false;
152 }
153 
FillBlacklistLogins(vector<PasswordForm * > * forms)154 bool PasswordStoreX::FillBlacklistLogins(vector<PasswordForm*>* forms) {
155   CheckMigration();
156   if (use_native_backend() && backend_->GetBlacklistLogins(forms)) {
157     allow_fallback_ = false;
158     return true;
159   }
160   if (allow_default_store())
161     return PasswordStoreDefault::FillBlacklistLogins(forms);
162   return false;
163 }
164 
CheckMigration()165 void PasswordStoreX::CheckMigration() {
166   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
167   if (migration_checked_ || !backend_.get())
168     return;
169   migration_checked_ = true;
170   ssize_t migrated = MigrateLogins();
171   if (migrated > 0) {
172     VLOG(1) << "Migrated " << migrated << " passwords to native store.";
173   } else if (migrated == 0) {
174     // As long as we are able to migrate some passwords, we know the native
175     // store is working. But if there is nothing to migrate, the "migration"
176     // can succeed even when the native store would fail. In this case we
177     // allow a later fallback to the default store. Once any later operation
178     // succeeds on the native store, we will no longer allow it.
179     allow_fallback_ = true;
180   } else {
181     LOG(WARNING) << "Native password store migration failed! " <<
182                  "Falling back on default (unencrypted) store.";
183     backend_.reset(NULL);
184   }
185 }
186 
allow_default_store()187 bool PasswordStoreX::allow_default_store() {
188   if (allow_fallback_) {
189     LOG(WARNING) << "Native password store failed! " <<
190                  "Falling back on default (unencrypted) store.";
191     backend_.reset(NULL);
192     // Don't warn again. We'll use the default store because backend_ is NULL.
193     allow_fallback_ = false;
194   }
195   return !backend_.get();
196 }
197 
MigrateLogins()198 ssize_t PasswordStoreX::MigrateLogins() {
199   DCHECK(backend_.get());
200   vector<PasswordForm*> forms;
201   bool ok = PasswordStoreDefault::FillAutofillableLogins(&forms) &&
202       PasswordStoreDefault::FillBlacklistLogins(&forms);
203   if (ok) {
204     // We add all the passwords (and blacklist entries) to the native backend
205     // before attempting to remove any from the login database, to make sure we
206     // don't somehow end up with some of the passwords in one store and some in
207     // another. We'll always have at least one intact store this way.
208     for (size_t i = 0; i < forms.size(); ++i) {
209       if (!backend_->AddLogin(*forms[i])) {
210         ok = false;
211         break;
212       }
213     }
214     if (forms.empty()) {
215       // If there's nothing to migrate, then we try to insert a dummy login form
216       // just to force the native store to unlock if it was locked. We delete it
217       // right away if we are successful. If the first operation we try to do is
218       // a read, then in some cases this is just an error rather than an action
219       // that causes the native store to prompt the user to unlock.
220       // TODO(mdm): this means we no longer need the allow_fallback mechanism.
221       // Remove it once this preemptive unlock by write is baked for a while.
222       PasswordForm dummy;
223       dummy.origin = GURL("http://www.example.com/force-keyring-unlock");
224       dummy.signon_realm = "www.example.com";
225       if (backend_->AddLogin(dummy))
226         backend_->RemoveLogin(dummy);
227       else
228         ok = false;
229     }
230     if (ok) {
231       for (size_t i = 0; i < forms.size(); ++i) {
232         // If even one of these calls to RemoveLoginImpl() succeeds, then we
233         // should prefer the native backend to the now-incomplete login
234         // database. Thus we want to return a success status even in the case
235         // where some fail. The only real problem with this is that we might
236         // leave passwords in the login database and never come back to clean
237         // them out if any of these calls do fail.
238         PasswordStoreDefault::RemoveLoginImpl(*forms[i]);
239       }
240       // Finally, delete the database file itself. We remove the passwords from
241       // it before deleting the file just in case there is some problem deleting
242       // the file (e.g. directory is not writable, but file is), which would
243       // otherwise cause passwords to re-migrate next (or maybe every) time.
244       DeleteAndRecreateDatabaseFile();
245     }
246   }
247   ssize_t result = ok ? forms.size() : -1;
248   STLDeleteElements(&forms);
249   return result;
250 }
251