Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(247)

Side by Side Diff: chrome/browser/password_manager/native_backend_kwallet_x.cc

Issue 906973007: PasswordStore: Clean up expectations about rewriting vectors of forms (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Just rebased Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/password_manager/native_backend_kwallet_x.h" 5 #include "chrome/browser/password_manager/native_backend_kwallet_x.h"
6 6
7 #include <vector> 7 #include <vector>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
11 #include "base/pickle.h" 11 #include "base/pickle.h"
12 #include "base/stl_util.h" 12 #include "base/stl_util.h"
13 #include "base/strings/stringprintf.h" 13 #include "base/strings/stringprintf.h"
14 #include "base/synchronization/waitable_event.h" 14 #include "base/synchronization/waitable_event.h"
15 #include "base/threading/thread_restrictions.h" 15 #include "base/threading/thread_restrictions.h"
16 #include "chrome/grit/chromium_strings.h" 16 #include "chrome/grit/chromium_strings.h"
17 #include "components/autofill/core/common/password_form.h" 17 #include "components/autofill/core/common/password_form.h"
18 #include "content/public/browser/browser_thread.h" 18 #include "content/public/browser/browser_thread.h"
19 #include "dbus/bus.h" 19 #include "dbus/bus.h"
20 #include "dbus/message.h" 20 #include "dbus/message.h"
21 #include "dbus/object_path.h" 21 #include "dbus/object_path.h"
22 #include "dbus/object_proxy.h" 22 #include "dbus/object_proxy.h"
23 #include "ui/base/l10n/l10n_util.h" 23 #include "ui/base/l10n/l10n_util.h"
24 24
25 using autofill::PasswordForm; 25 using autofill::PasswordForm;
26 using content::BrowserThread; 26 using content::BrowserThread;
27 27
28 namespace { 28 namespace {
29 29
30 // In case the fields in the pickle ever change, version them so we can try to
31 // read old pickles. (Note: do not eat old pickles past the expiration date.)
32 const int kPickleVersion = 6;
33
30 // We could localize this string, but then changing your locale would cause 34 // We could localize this string, but then changing your locale would cause
31 // you to lose access to all your stored passwords. Maybe best not to do that. 35 // you to lose access to all your stored passwords. Maybe best not to do that.
32 // Name of the folder to store passwords in. 36 // Name of the folder to store passwords in.
33 const char kKWalletFolder[] = "Chrome Form Data"; 37 const char kKWalletFolder[] = "Chrome Form Data";
34 38
35 // DBus service, path, and interface names for klauncher and kwalletd. 39 // DBus service, path, and interface names for klauncher and kwalletd.
36 const char kKWalletServiceName[] = "org.kde.kwalletd"; 40 const char kKWalletServiceName[] = "org.kde.kwalletd";
37 const char kKWalletPath[] = "/modules/kwalletd"; 41 const char kKWalletPath[] = "/modules/kwalletd";
38 const char kKWalletInterface[] = "org.kde.KWallet"; 42 const char kKWalletInterface[] = "org.kde.KWallet";
39 const char kKLauncherServiceName[] = "org.kde.klauncher"; 43 const char kKLauncherServiceName[] = "org.kde.klauncher";
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
93 LOG(WARNING) << "Failed to deserialize version " << version 97 LOG(WARNING) << "Failed to deserialize version " << version
94 << " KWallet entry (realm: " << signon_realm 98 << " KWallet entry (realm: " << signon_realm
95 << ") with native architecture size; will try alternate " 99 << ") with native architecture size; will try alternate "
96 << "size."; 100 << "size.";
97 } else { 101 } else {
98 LOG(ERROR) << "Failed to deserialize version " << version 102 LOG(ERROR) << "Failed to deserialize version " << version
99 << " KWallet entry (realm: " << signon_realm << ")"; 103 << " KWallet entry (realm: " << signon_realm << ")";
100 } 104 }
101 } 105 }
102 106
107 // Deserializes a list of credentials from the wallet to |forms| (replacing
108 // the contents of |forms|). |size_32| controls reading the size field within
109 // the pickle as 32 bits. We used to use Pickle::WriteSize() to write the number
110 // of password forms, but that has a different size on 32- and 64-bit systems.
111 // So, now we always write a 64-bit quantity, but we support trying to read it
112 // as either size when reading old pickles that fail to deserialize using the
113 // native size. Returns true on success.
114 bool DeserializeValueSize(const std::string& signon_realm,
115 const PickleIterator& init_iter,
116 int version,
117 bool size_32,
118 bool warn_only,
119 ScopedVector<autofill::PasswordForm>* forms) {
120 PickleIterator iter = init_iter;
121
122 size_t count = 0;
123 if (size_32) {
124 uint32_t count_32 = 0;
125 if (!iter.ReadUInt32(&count_32)) {
126 LOG(ERROR) << "Failed to deserialize KWallet entry "
127 << "(realm: " << signon_realm << ")";
128 return false;
129 }
130 count = count_32;
131 } else {
132 if (!iter.ReadSizeT(&count)) {
133 LOG(ERROR) << "Failed to deserialize KWallet entry "
134 << "(realm: " << signon_realm << ")";
135 return false;
136 }
137 }
138
139 if (count > 0xFFFF) {
140 // Trying to pin down the cause of http://crbug.com/80728 (or fix it).
141 // This is a very large number of passwords to be saved for a single realm.
142 // It is almost certainly a corrupt pickle and not real data. Ignore it.
143 // This very well might actually be http://crbug.com/107701, so if we're
144 // reading an old pickle, we don't even log this the first time we try to
145 // read it. (That is, when we're reading the native architecture size.)
146 if (!warn_only) {
147 LOG(ERROR) << "Suspiciously large number of entries in KWallet entry "
148 << "(" << count << "; realm: " << signon_realm << ")";
149 }
150 return false;
151 }
152
153 // We'll swap |converted_forms| with |*forms| on success, to make sure we
154 // don't return partial results on failure.
155 ScopedVector<autofill::PasswordForm> converted_forms;
156 converted_forms.reserve(count);
157 for (size_t i = 0; i < count; ++i) {
158 scoped_ptr<PasswordForm> form(new PasswordForm());
159 form->signon_realm.assign(signon_realm);
160
161 int scheme = 0;
162 int64 date_created = 0;
163 int type = 0;
164 int generation_upload_status = 0;
165 // Note that these will be read back in the order listed due to
166 // short-circuit evaluation. This is important.
167 if (!iter.ReadInt(&scheme) ||
168 !ReadGURL(&iter, warn_only, &form->origin) ||
169 !ReadGURL(&iter, warn_only, &form->action) ||
170 !iter.ReadString16(&form->username_element) ||
171 !iter.ReadString16(&form->username_value) ||
172 !iter.ReadString16(&form->password_element) ||
173 !iter.ReadString16(&form->password_value) ||
174 !iter.ReadString16(&form->submit_element) ||
175 !iter.ReadBool(&form->ssl_valid) ||
176 !iter.ReadBool(&form->preferred) ||
177 !iter.ReadBool(&form->blacklisted_by_user) ||
178 !iter.ReadInt64(&date_created)) {
179 LogDeserializationWarning(version, signon_realm, warn_only);
180 return false;
181 }
182 form->scheme = static_cast<PasswordForm::Scheme>(scheme);
183
184 if (version > 1) {
185 if (!iter.ReadInt(&type) ||
186 !iter.ReadInt(&form->times_used) ||
187 !autofill::DeserializeFormData(&iter, &form->form_data)) {
188 LogDeserializationWarning(version, signon_realm, false);
189 return false;
190 }
191 form->type = static_cast<PasswordForm::Type>(type);
192 }
193
194 if (version > 2) {
195 int64 date_synced = 0;
196 if (!iter.ReadInt64(&date_synced)) {
197 LogDeserializationWarning(version, signon_realm, false);
198 return false;
199 }
200 form->date_synced = base::Time::FromInternalValue(date_synced);
201 }
202
203 if (version > 3) {
204 if (!iter.ReadString16(&form->display_name) ||
205 !ReadGURL(&iter, warn_only, &form->avatar_url) ||
206 !ReadGURL(&iter, warn_only, &form->federation_url) ||
207 !iter.ReadBool(&form->skip_zero_click)) {
208 LogDeserializationWarning(version, signon_realm, false);
209 return false;
210 }
211 }
212
213 if (version > 4) {
214 form->date_created = base::Time::FromInternalValue(date_created);
215 } else {
216 form->date_created = base::Time::FromTimeT(date_created);
217 }
218
219 if (version > 5) {
220 if (!iter.ReadInt(&generation_upload_status)) {
221 LogDeserializationWarning(version, signon_realm, false);
222 }
223 form->generation_upload_status =
224 static_cast<PasswordForm::GenerationUploadStatus>(
225 generation_upload_status);
226 }
227
228 converted_forms.push_back(form.release());
229 }
230
231 forms->swap(converted_forms);
232 return true;
233 }
234
235 // Serializes a list of PasswordForms to be stored in the wallet.
236 void SerializeValue(const std::vector<autofill::PasswordForm*>& forms,
237 Pickle* pickle) {
238 pickle->WriteInt(kPickleVersion);
239 pickle->WriteSizeT(forms.size());
240 for (autofill::PasswordForm* form : forms) {
241 pickle->WriteInt(form->scheme);
242 pickle->WriteString(form->origin.spec());
243 pickle->WriteString(form->action.spec());
244 pickle->WriteString16(form->username_element);
245 pickle->WriteString16(form->username_value);
246 pickle->WriteString16(form->password_element);
247 pickle->WriteString16(form->password_value);
248 pickle->WriteString16(form->submit_element);
249 pickle->WriteBool(form->ssl_valid);
250 pickle->WriteBool(form->preferred);
251 pickle->WriteBool(form->blacklisted_by_user);
252 pickle->WriteInt64(form->date_created.ToInternalValue());
253 pickle->WriteInt(form->type);
254 pickle->WriteInt(form->times_used);
255 autofill::SerializeFormData(form->form_data, pickle);
256 pickle->WriteInt64(form->date_synced.ToInternalValue());
257 pickle->WriteString16(form->display_name);
258 pickle->WriteString(form->avatar_url.spec());
259 pickle->WriteString(form->federation_url.spec());
260 pickle->WriteBool(form->skip_zero_click);
261 }
262 }
263
264 // Moves the content of |second| to the end of |first|.
265 void AppendSecondToFirst(ScopedVector<autofill::PasswordForm>* first,
266 ScopedVector<autofill::PasswordForm> second) {
267 first->reserve(first->size() + second.size());
268 first->insert(first->end(), second.begin(), second.end());
269 second.weak_clear();
270 }
271
103 } // namespace 272 } // namespace
104 273
105 NativeBackendKWallet::NativeBackendKWallet(LocalProfileId id) 274 NativeBackendKWallet::NativeBackendKWallet(LocalProfileId id)
106 : profile_id_(id), 275 : profile_id_(id),
107 kwallet_proxy_(nullptr), 276 kwallet_proxy_(nullptr),
108 app_name_(l10n_util::GetStringUTF8(IDS_PRODUCT_NAME)) { 277 app_name_(l10n_util::GetStringUTF8(IDS_PRODUCT_NAME)) {
109 folder_name_ = GetProfileSpecificFolderName(); 278 folder_name_ = GetProfileSpecificFolderName();
110 } 279 }
111 280
112 NativeBackendKWallet::~NativeBackendKWallet() { 281 NativeBackendKWallet::~NativeBackendKWallet() {
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after
265 return INIT_SUCCESS; 434 return INIT_SUCCESS;
266 } 435 }
267 436
268 password_manager::PasswordStoreChangeList NativeBackendKWallet::AddLogin( 437 password_manager::PasswordStoreChangeList NativeBackendKWallet::AddLogin(
269 const PasswordForm& form) { 438 const PasswordForm& form) {
270 int wallet_handle = WalletHandle(); 439 int wallet_handle = WalletHandle();
271 if (wallet_handle == kInvalidKWalletHandle) 440 if (wallet_handle == kInvalidKWalletHandle)
272 return password_manager::PasswordStoreChangeList(); 441 return password_manager::PasswordStoreChangeList();
273 442
274 ScopedVector<autofill::PasswordForm> forms; 443 ScopedVector<autofill::PasswordForm> forms;
275 GetLoginsList(form.signon_realm, wallet_handle, &forms); 444 if (!GetLoginsList(form.signon_realm, wallet_handle, &forms))
445 return password_manager::PasswordStoreChangeList();
276 446
277 // We search for a login to update, rather than unconditionally appending the 447 // We search for a login to update, rather than unconditionally appending the
278 // login, because in some cases (especially involving sync) we can be asked to 448 // login, because in some cases (especially involving sync) we can be asked to
279 // add a login that already exists. In these cases we want to just update. 449 // add a login that already exists. In these cases we want to just update.
280 bool updated = false; 450 bool updated = false;
281 password_manager::PasswordStoreChangeList changes; 451 password_manager::PasswordStoreChangeList changes;
282 for (size_t i = 0; i < forms.size(); ++i) { 452 for (size_t i = 0; i < forms.size(); ++i) {
283 // Use the more restrictive removal comparison, so that we never have 453 // Use the more restrictive removal comparison, so that we never have
284 // duplicate logins that would all be removed together by RemoveLogin(). 454 // duplicate logins that would all be removed together by RemoveLogin().
285 if (CompareForms(form, *forms[i], false)) { 455 if (CompareForms(form, *forms[i], false)) {
(...skipping 18 matching lines...) Expand all
304 bool NativeBackendKWallet::UpdateLogin( 474 bool NativeBackendKWallet::UpdateLogin(
305 const PasswordForm& form, 475 const PasswordForm& form,
306 password_manager::PasswordStoreChangeList* changes) { 476 password_manager::PasswordStoreChangeList* changes) {
307 DCHECK(changes); 477 DCHECK(changes);
308 changes->clear(); 478 changes->clear();
309 int wallet_handle = WalletHandle(); 479 int wallet_handle = WalletHandle();
310 if (wallet_handle == kInvalidKWalletHandle) 480 if (wallet_handle == kInvalidKWalletHandle)
311 return false; 481 return false;
312 482
313 ScopedVector<autofill::PasswordForm> forms; 483 ScopedVector<autofill::PasswordForm> forms;
314 GetLoginsList(form.signon_realm, wallet_handle, &forms); 484 if (!GetLoginsList(form.signon_realm, wallet_handle, &forms))
485 return false;
315 486
316 bool updated = false; 487 bool updated = false;
317 for (size_t i = 0; i < forms.size(); ++i) { 488 for (size_t i = 0; i < forms.size(); ++i) {
318 if (CompareForms(form, *forms[i], true)) { 489 if (CompareForms(form, *forms[i], true)) {
319 *forms[i] = form; 490 *forms[i] = form;
320 updated = true; 491 updated = true;
321 } 492 }
322 } 493 }
323 if (!updated) 494 if (!updated)
324 return true; 495 return true;
325 496
326 if (SetLoginsList(forms.get(), form.signon_realm, wallet_handle)) { 497 if (SetLoginsList(forms.get(), form.signon_realm, wallet_handle)) {
327 changes->push_back(password_manager::PasswordStoreChange( 498 changes->push_back(password_manager::PasswordStoreChange(
328 password_manager::PasswordStoreChange::UPDATE, form)); 499 password_manager::PasswordStoreChange::UPDATE, form));
329 return true; 500 return true;
330 } 501 }
331 502
332 return false; 503 return false;
333 } 504 }
334 505
335 bool NativeBackendKWallet::RemoveLogin(const PasswordForm& form) { 506 bool NativeBackendKWallet::RemoveLogin(const PasswordForm& form) {
336 int wallet_handle = WalletHandle(); 507 int wallet_handle = WalletHandle();
337 if (wallet_handle == kInvalidKWalletHandle) 508 if (wallet_handle == kInvalidKWalletHandle)
338 return false; 509 return false;
339 510
340 ScopedVector<autofill::PasswordForm> all_forms; 511 ScopedVector<autofill::PasswordForm> all_forms;
341 GetLoginsList(form.signon_realm, wallet_handle, &all_forms); 512 if (!GetLoginsList(form.signon_realm, wallet_handle, &all_forms))
513 return false;
342 514
343 ScopedVector<autofill::PasswordForm> kept_forms; 515 ScopedVector<autofill::PasswordForm> kept_forms;
344 kept_forms.reserve(all_forms.size()); 516 kept_forms.reserve(all_forms.size());
345 for (auto& saved_form : all_forms) { 517 for (auto& saved_form : all_forms) {
346 if (!CompareForms(form, *saved_form, false)) { 518 if (!CompareForms(form, *saved_form, false)) {
347 kept_forms.push_back(saved_form); 519 kept_forms.push_back(saved_form);
348 saved_form = nullptr; 520 saved_form = nullptr;
349 } 521 }
350 } 522 }
351 523
(...skipping 23 matching lines...) Expand all
375 if (wallet_handle == kInvalidKWalletHandle) 547 if (wallet_handle == kInvalidKWalletHandle)
376 return false; 548 return false;
377 return GetLoginsList(form.signon_realm, wallet_handle, forms); 549 return GetLoginsList(form.signon_realm, wallet_handle, forms);
378 } 550 }
379 551
380 bool NativeBackendKWallet::GetAutofillableLogins( 552 bool NativeBackendKWallet::GetAutofillableLogins(
381 ScopedVector<autofill::PasswordForm>* forms) { 553 ScopedVector<autofill::PasswordForm>* forms) {
382 int wallet_handle = WalletHandle(); 554 int wallet_handle = WalletHandle();
383 if (wallet_handle == kInvalidKWalletHandle) 555 if (wallet_handle == kInvalidKWalletHandle)
384 return false; 556 return false;
385 return GetLoginsList(true, wallet_handle, forms); 557 return GetLoginsList(BlacklistOptions::AUTOFILLABLE, wallet_handle, forms);
386 } 558 }
387 559
388 bool NativeBackendKWallet::GetBlacklistLogins( 560 bool NativeBackendKWallet::GetBlacklistLogins(
389 ScopedVector<autofill::PasswordForm>* forms) { 561 ScopedVector<autofill::PasswordForm>* forms) {
390 int wallet_handle = WalletHandle(); 562 int wallet_handle = WalletHandle();
391 if (wallet_handle == kInvalidKWalletHandle) 563 if (wallet_handle == kInvalidKWalletHandle)
392 return false; 564 return false;
393 return GetLoginsList(false, wallet_handle, forms); 565 return GetLoginsList(BlacklistOptions::BLACKLISTED, wallet_handle, forms);
394 } 566 }
395 567
396 bool NativeBackendKWallet::GetLoginsList( 568 bool NativeBackendKWallet::GetLoginsList(
397 const std::string& signon_realm, 569 const std::string& signon_realm,
398 int wallet_handle, 570 int wallet_handle,
399 ScopedVector<autofill::PasswordForm>* forms) { 571 ScopedVector<autofill::PasswordForm>* forms) {
572 forms->clear();
400 // Is there an entry in the wallet? 573 // Is there an entry in the wallet?
401 { 574 {
402 dbus::MethodCall method_call(kKWalletInterface, "hasEntry"); 575 dbus::MethodCall method_call(kKWalletInterface, "hasEntry");
403 dbus::MessageWriter builder(&method_call); 576 dbus::MessageWriter builder(&method_call);
404 builder.AppendInt32(wallet_handle); // handle 577 builder.AppendInt32(wallet_handle); // handle
405 builder.AppendString(folder_name_); // folder 578 builder.AppendString(folder_name_); // folder
406 builder.AppendString(signon_realm); // key 579 builder.AppendString(signon_realm); // key
407 builder.AppendString(app_name_); // appid 580 builder.AppendString(app_name_); // appid
408 scoped_ptr<dbus::Response> response( 581 scoped_ptr<dbus::Response> response(
409 kwallet_proxy_->CallMethodAndBlock( 582 kwallet_proxy_->CallMethodAndBlock(
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
452 if (!CheckSerializedValue(bytes, length, signon_realm)) { 625 if (!CheckSerializedValue(bytes, length, signon_realm)) {
453 // This is weird, but we choose not to call it an error. There is an 626 // This is weird, but we choose not to call it an error. There is an
454 // invalid entry somehow, but by just ignoring it, we make it easier to 627 // invalid entry somehow, but by just ignoring it, we make it easier to
455 // repair without having to delete it using kwalletmanager (that is, by 628 // repair without having to delete it using kwalletmanager (that is, by
456 // just saving a new password within this realm to overwrite it). 629 // just saving a new password within this realm to overwrite it).
457 return true; 630 return true;
458 } 631 }
459 632
460 // Can't we all just agree on whether bytes are signed or not? Please? 633 // Can't we all just agree on whether bytes are signed or not? Please?
461 Pickle pickle(reinterpret_cast<const char*>(bytes), length); 634 Pickle pickle(reinterpret_cast<const char*>(bytes), length);
462 DeserializeValue(signon_realm, pickle, forms); 635 *forms = DeserializeValue(signon_realm, pickle);
463 } 636 }
464 637
465 return true; 638 return true;
466 } 639 }
467 640
468 bool NativeBackendKWallet::GetLoginsList( 641 bool NativeBackendKWallet::GetLoginsList(
469 bool autofillable, 642 BlacklistOptions options,
470 int wallet_handle, 643 int wallet_handle,
471 ScopedVector<autofill::PasswordForm>* forms) { 644 ScopedVector<autofill::PasswordForm>* forms) {
645 forms->clear();
472 ScopedVector<autofill::PasswordForm> all_forms; 646 ScopedVector<autofill::PasswordForm> all_forms;
473 if (!GetAllLogins(wallet_handle, &all_forms)) 647 if (!GetAllLogins(wallet_handle, &all_forms))
474 return false; 648 return false;
475 649
476 // We have to read all the entries, and then filter them here. 650 // We have to read all the entries, and then filter them here.
477 forms->reserve(forms->size() + all_forms.size()); 651 forms->reserve(all_forms.size());
478 for (auto& saved_form : all_forms) { 652 for (auto& saved_form : all_forms) {
479 if (saved_form->blacklisted_by_user == !autofillable) { 653 if (saved_form->blacklisted_by_user ==
654 (options == BlacklistOptions::BLACKLISTED)) {
480 forms->push_back(saved_form); 655 forms->push_back(saved_form);
481 saved_form = nullptr; 656 saved_form = nullptr;
482 } 657 }
483 } 658 }
484 659
485 return true; 660 return true;
486 } 661 }
487 662
488 bool NativeBackendKWallet::GetAllLogins( 663 bool NativeBackendKWallet::GetAllLogins(
489 int wallet_handle, 664 int wallet_handle,
(...skipping 14 matching lines...) Expand all
504 return false; 679 return false;
505 } 680 }
506 dbus::MessageReader reader(response.get()); 681 dbus::MessageReader reader(response.get());
507 if (!reader.PopArrayOfStrings(&realm_list)) { 682 if (!reader.PopArrayOfStrings(&realm_list)) {
508 LOG(ERROR) << "Error reading response from kwalletd (entryList): " 683 LOG(ERROR) << "Error reading response from kwalletd (entryList): "
509 << response->ToString(); 684 << response->ToString();
510 return false; 685 return false;
511 } 686 }
512 } 687 }
513 688
514 for (size_t i = 0; i < realm_list.size(); ++i) { 689 forms->clear();
515 const std::string& signon_realm = realm_list[i]; 690 for (const std::string& signon_realm : realm_list) {
516 dbus::MethodCall method_call(kKWalletInterface, "readEntry"); 691 dbus::MethodCall method_call(kKWalletInterface, "readEntry");
517 dbus::MessageWriter builder(&method_call); 692 dbus::MessageWriter builder(&method_call);
518 builder.AppendInt32(wallet_handle); // handle 693 builder.AppendInt32(wallet_handle); // handle
519 builder.AppendString(folder_name_); // folder 694 builder.AppendString(folder_name_); // folder
520 builder.AppendString(signon_realm); // key 695 builder.AppendString(signon_realm); // key
521 builder.AppendString(app_name_); // appid 696 builder.AppendString(app_name_); // appid
522 scoped_ptr<dbus::Response> response( 697 scoped_ptr<dbus::Response> response(
523 kwallet_proxy_->CallMethodAndBlock( 698 kwallet_proxy_->CallMethodAndBlock(
524 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT)); 699 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
525 if (!response.get()) { 700 if (!response.get()) {
526 LOG(ERROR) << "Error contacting kwalletd (readEntry)"; 701 LOG(ERROR) << "Error contacting kwalletd (readEntry)";
527 return false; 702 return false;
528 } 703 }
529 dbus::MessageReader reader(response.get()); 704 dbus::MessageReader reader(response.get());
530 const uint8_t* bytes = nullptr; 705 const uint8_t* bytes = nullptr;
531 size_t length = 0; 706 size_t length = 0;
532 if (!reader.PopArrayOfBytes(&bytes, &length)) { 707 if (!reader.PopArrayOfBytes(&bytes, &length)) {
533 LOG(ERROR) << "Error reading response from kwalletd (readEntry): " 708 LOG(ERROR) << "Error reading response from kwalletd (readEntry): "
534 << response->ToString(); 709 << response->ToString();
535 return false; 710 return false;
536 } 711 }
537 if (!bytes || !CheckSerializedValue(bytes, length, signon_realm)) 712 if (!bytes || !CheckSerializedValue(bytes, length, signon_realm))
538 continue; 713 continue;
539 714
540 // Can't we all just agree on whether bytes are signed or not? Please? 715 // Can't we all just agree on whether bytes are signed or not? Please?
541 Pickle pickle(reinterpret_cast<const char*>(bytes), length); 716 Pickle pickle(reinterpret_cast<const char*>(bytes), length);
542 DeserializeValue(signon_realm, pickle, forms); 717 AppendSecondToFirst(forms, DeserializeValue(signon_realm, pickle));
543 } 718 }
544 return true; 719 return true;
545 } 720 }
546 721
547 bool NativeBackendKWallet::SetLoginsList( 722 bool NativeBackendKWallet::SetLoginsList(
548 const std::vector<autofill::PasswordForm*>& forms, 723 const std::vector<autofill::PasswordForm*>& forms,
549 const std::string& signon_realm, 724 const std::string& signon_realm,
550 int wallet_handle) { 725 int wallet_handle) {
551 if (forms.empty()) { 726 if (forms.empty()) {
552 // No items left? Remove the entry from the wallet. 727 // No items left? Remove the entry from the wallet.
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after
669 if (!reader.PopArrayOfBytes(&bytes, &length)) { 844 if (!reader.PopArrayOfBytes(&bytes, &length)) {
670 LOG(ERROR) << "Error reading response from kwalletd (readEntry): " 845 LOG(ERROR) << "Error reading response from kwalletd (readEntry): "
671 << response->ToString(); 846 << response->ToString();
672 continue; 847 continue;
673 } 848 }
674 if (!bytes || !CheckSerializedValue(bytes, length, signon_realm)) 849 if (!bytes || !CheckSerializedValue(bytes, length, signon_realm))
675 continue; 850 continue;
676 851
677 // Can't we all just agree on whether bytes are signed or not? Please? 852 // Can't we all just agree on whether bytes are signed or not? Please?
678 Pickle pickle(reinterpret_cast<const char*>(bytes), length); 853 Pickle pickle(reinterpret_cast<const char*>(bytes), length);
679 ScopedVector<autofill::PasswordForm> all_forms; 854 ScopedVector<autofill::PasswordForm> all_forms =
680 DeserializeValue(signon_realm, pickle, &all_forms); 855 DeserializeValue(signon_realm, pickle);
681 856
682 ScopedVector<autofill::PasswordForm> kept_forms; 857 ScopedVector<autofill::PasswordForm> kept_forms;
683 kept_forms.reserve(all_forms.size()); 858 kept_forms.reserve(all_forms.size());
684 base::Time autofill::PasswordForm::*date_member = 859 base::Time autofill::PasswordForm::*date_member =
685 date_to_compare == CREATION_TIMESTAMP 860 date_to_compare == CREATION_TIMESTAMP
686 ? &autofill::PasswordForm::date_created 861 ? &autofill::PasswordForm::date_created
687 : &autofill::PasswordForm::date_synced; 862 : &autofill::PasswordForm::date_synced;
688 for (auto& saved_form : all_forms) { 863 for (auto& saved_form : all_forms) {
689 if (delete_begin <= saved_form->*date_member && 864 if (delete_begin <= saved_form->*date_member &&
690 (delete_end.is_null() || saved_form->*date_member < delete_end)) { 865 (delete_end.is_null() || saved_form->*date_member < delete_end)) {
691 changes->push_back(password_manager::PasswordStoreChange( 866 changes->push_back(password_manager::PasswordStoreChange(
692 password_manager::PasswordStoreChange::REMOVE, *saved_form)); 867 password_manager::PasswordStoreChange::REMOVE, *saved_form));
693 } else { 868 } else {
694 kept_forms.push_back(saved_form); 869 kept_forms.push_back(saved_form);
695 saved_form = nullptr; 870 saved_form = nullptr;
696 } 871 }
697 } 872 }
698 873
699 if (!SetLoginsList(kept_forms.get(), signon_realm, wallet_handle)) { 874 if (!SetLoginsList(kept_forms.get(), signon_realm, wallet_handle)) {
700 ok = false; 875 ok = false;
701 changes->clear(); 876 changes->clear();
702 } 877 }
703 } 878 }
704 return ok; 879 return ok;
705 } 880 }
706 881
707 // static 882 // static
708 void NativeBackendKWallet::SerializeValue( 883 ScopedVector<autofill::PasswordForm> NativeBackendKWallet::DeserializeValue(
709 const std::vector<autofill::PasswordForm*>& forms,
710 Pickle* pickle) {
711 pickle->WriteInt(kPickleVersion);
712 pickle->WriteSizeT(forms.size());
713 for (autofill::PasswordForm* form : forms) {
714 pickle->WriteInt(form->scheme);
715 pickle->WriteString(form->origin.spec());
716 pickle->WriteString(form->action.spec());
717 pickle->WriteString16(form->username_element);
718 pickle->WriteString16(form->username_value);
719 pickle->WriteString16(form->password_element);
720 pickle->WriteString16(form->password_value);
721 pickle->WriteString16(form->submit_element);
722 pickle->WriteBool(form->ssl_valid);
723 pickle->WriteBool(form->preferred);
724 pickle->WriteBool(form->blacklisted_by_user);
725 pickle->WriteInt64(form->date_created.ToInternalValue());
726 pickle->WriteInt(form->type);
727 pickle->WriteInt(form->times_used);
728 autofill::SerializeFormData(form->form_data, pickle);
729 pickle->WriteInt64(form->date_synced.ToInternalValue());
730 pickle->WriteString16(form->display_name);
731 pickle->WriteString(form->avatar_url.spec());
732 pickle->WriteString(form->federation_url.spec());
733 pickle->WriteBool(form->skip_zero_click);
734 pickle->WriteInt(form->generation_upload_status);
735 }
736 }
737
738 // static
739 bool NativeBackendKWallet::DeserializeValueSize(
740 const std::string& signon_realm, 884 const std::string& signon_realm,
741 const PickleIterator& init_iter, 885 const Pickle& pickle) {
742 int version,
743 bool size_32,
744 bool warn_only,
745 ScopedVector<autofill::PasswordForm>* forms) {
746 PickleIterator iter = init_iter;
747
748 size_t count = 0;
749 if (size_32) {
750 uint32_t count_32 = 0;
751 if (!iter.ReadUInt32(&count_32)) {
752 LOG(ERROR) << "Failed to deserialize KWallet entry "
753 << "(realm: " << signon_realm << ")";
754 return false;
755 }
756 count = count_32;
757 } else {
758 if (!iter.ReadSizeT(&count)) {
759 LOG(ERROR) << "Failed to deserialize KWallet entry "
760 << "(realm: " << signon_realm << ")";
761 return false;
762 }
763 }
764
765 if (count > 0xFFFF) {
766 // Trying to pin down the cause of http://crbug.com/80728 (or fix it).
767 // This is a very large number of passwords to be saved for a single realm.
768 // It is almost certainly a corrupt pickle and not real data. Ignore it.
769 // This very well might actually be http://crbug.com/107701, so if we're
770 // reading an old pickle, we don't even log this the first time we try to
771 // read it. (That is, when we're reading the native architecture size.)
772 if (!warn_only) {
773 LOG(ERROR) << "Suspiciously large number of entries in KWallet entry "
774 << "(" << count << "; realm: " << signon_realm << ")";
775 }
776 return false;
777 }
778
779 forms->reserve(forms->size() + count);
780 for (size_t i = 0; i < count; ++i) {
781 scoped_ptr<PasswordForm> form(new PasswordForm());
782 form->signon_realm.assign(signon_realm);
783
784 int scheme = 0;
785 int64 date_created = 0;
786 int type = 0;
787 int generation_upload_status = 0;
788 // Note that these will be read back in the order listed due to
789 // short-circuit evaluation. This is important.
790 if (!iter.ReadInt(&scheme) ||
791 !ReadGURL(&iter, warn_only, &form->origin) ||
792 !ReadGURL(&iter, warn_only, &form->action) ||
793 !iter.ReadString16(&form->username_element) ||
794 !iter.ReadString16(&form->username_value) ||
795 !iter.ReadString16(&form->password_element) ||
796 !iter.ReadString16(&form->password_value) ||
797 !iter.ReadString16(&form->submit_element) ||
798 !iter.ReadBool(&form->ssl_valid) ||
799 !iter.ReadBool(&form->preferred) ||
800 !iter.ReadBool(&form->blacklisted_by_user) ||
801 !iter.ReadInt64(&date_created)) {
802 LogDeserializationWarning(version, signon_realm, warn_only);
803 return false;
804 }
805 form->scheme = static_cast<PasswordForm::Scheme>(scheme);
806
807 if (version > 1) {
808 if (!iter.ReadInt(&type) ||
809 !iter.ReadInt(&form->times_used) ||
810 !autofill::DeserializeFormData(&iter, &form->form_data)) {
811 LogDeserializationWarning(version, signon_realm, false);
812 return false;
813 }
814 form->type = static_cast<PasswordForm::Type>(type);
815 }
816
817 if (version > 2) {
818 int64 date_synced = 0;
819 if (!iter.ReadInt64(&date_synced)) {
820 LogDeserializationWarning(version, signon_realm, false);
821 return false;
822 }
823 form->date_synced = base::Time::FromInternalValue(date_synced);
824 }
825
826 if (version > 3) {
827 if (!iter.ReadString16(&form->display_name) ||
828 !ReadGURL(&iter, warn_only, &form->avatar_url) ||
829 !ReadGURL(&iter, warn_only, &form->federation_url) ||
830 !iter.ReadBool(&form->skip_zero_click)) {
831 LogDeserializationWarning(version, signon_realm, false);
832 return false;
833 }
834 }
835
836 if (version > 4) {
837 form->date_created = base::Time::FromInternalValue(date_created);
838 } else {
839 form->date_created = base::Time::FromTimeT(date_created);
840 }
841
842 if (version > 5) {
843 if (!iter.ReadInt(&generation_upload_status)) {
844 LogDeserializationWarning(version, signon_realm, false);
845 }
846 form->generation_upload_status =
847 static_cast<PasswordForm::GenerationUploadStatus>(
848 generation_upload_status);
849 }
850
851 forms->push_back(form.release());
852 }
853
854 return true;
855 }
856
857 // static
858 void NativeBackendKWallet::DeserializeValue(
859 const std::string& signon_realm,
860 const Pickle& pickle,
861 ScopedVector<autofill::PasswordForm>* forms) {
862 PickleIterator iter(pickle); 886 PickleIterator iter(pickle);
863 887
864 int version = -1; 888 int version = -1;
865 if (!iter.ReadInt(&version) || 889 if (!iter.ReadInt(&version) ||
866 version < 0 || version > kPickleVersion) { 890 version < 0 || version > kPickleVersion) {
867 LOG(ERROR) << "Failed to deserialize KWallet entry " 891 LOG(ERROR) << "Failed to deserialize KWallet entry "
868 << "(realm: " << signon_realm << ")"; 892 << "(realm: " << signon_realm << ")";
869 return; 893 return ScopedVector<autofill::PasswordForm>();
870 } 894 }
871 895
896 ScopedVector<autofill::PasswordForm> forms;
872 if (version > 0) { 897 if (version > 0) {
873 // In current pickles, we expect 64-bit sizes. Failure is an error. 898 // In current pickles, we expect 64-bit sizes. Failure is an error.
874 DeserializeValueSize(signon_realm, iter, version, false, false, forms); 899 DeserializeValueSize(signon_realm, iter, version, false, false, &forms);
875 return; 900 return forms.Pass();
876 } 901 }
877 902
878 const size_t saved_forms_size = forms->size();
879 const bool size_32 = sizeof(size_t) == sizeof(uint32_t); 903 const bool size_32 = sizeof(size_t) == sizeof(uint32_t);
880 if (!DeserializeValueSize( 904 if (!DeserializeValueSize(
881 signon_realm, iter, version, size_32, true, forms)) { 905 signon_realm, iter, version, size_32, true, &forms)) {
882 // We failed to read the pickle using the native architecture of the system. 906 // We failed to read the pickle using the native architecture of the system.
883 // Try again with the opposite architecture. Note that we do this even on 907 // Try again with the opposite architecture. Note that we do this even on
884 // 32-bit machines, in case we're reading a 64-bit pickle. (Probably rare, 908 // 32-bit machines, in case we're reading a 64-bit pickle. (Probably rare,
885 // since mostly we expect upgrades, not downgrades, but both are possible.) 909 // since mostly we expect upgrades, not downgrades, but both are possible.)
886 forms->resize(saved_forms_size); 910 DeserializeValueSize(signon_realm, iter, version, !size_32, false, &forms);
887 DeserializeValueSize(signon_realm, iter, version, !size_32, false, forms);
888 } 911 }
912 return forms.Pass();
889 } 913 }
890 914
891 int NativeBackendKWallet::WalletHandle() { 915 int NativeBackendKWallet::WalletHandle() {
892 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); 916 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
893 917
894 // Open the wallet. 918 // Open the wallet.
895 // TODO(mdm): Are we leaking these handles? Find out. 919 // TODO(mdm): Are we leaking these handles? Find out.
896 int32_t handle = kInvalidKWalletHandle; 920 int32_t handle = kInvalidKWalletHandle;
897 { 921 {
898 dbus::MethodCall method_call(kKWalletInterface, "open"); 922 dbus::MethodCall method_call(kKWalletInterface, "open");
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
970 } 994 }
971 995
972 return handle; 996 return handle;
973 } 997 }
974 998
975 std::string NativeBackendKWallet::GetProfileSpecificFolderName() const { 999 std::string NativeBackendKWallet::GetProfileSpecificFolderName() const {
976 // Originally, the folder name was always just "Chrome Form Data". 1000 // Originally, the folder name was always just "Chrome Form Data".
977 // Now we use it to distinguish passwords for different profiles. 1001 // Now we use it to distinguish passwords for different profiles.
978 return base::StringPrintf("%s (%d)", kKWalletFolder, profile_id_); 1002 return base::StringPrintf("%s (%d)", kKWalletFolder, profile_id_);
979 } 1003 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698