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

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: Created 5 years, 10 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 = 5;
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 // |forms| contents). |size_32| controls reading the size field within the
109 // pickle as 32 bits. We used to use Pickle::WriteSize() to write the number of
110 // password forms, but that has a different size on 32- and 64-bit systems. So,
111 // now we always write a 64-bit quantity, but we support trying to read it as
112 // either size when reading old pickles that fail to deserialize using the
113 // native size. Returns true on success, false on failure (erasing |forms| in
114 // that case).
115 bool DeserializeValueSize(const std::string& signon_realm,
116 const PickleIterator& init_iter,
117 int version,
118 bool size_32,
119 bool warn_only,
120 ScopedVector<autofill::PasswordForm>* forms) {
121 forms->clear();
122 PickleIterator iter = init_iter;
123
124 size_t count = 0;
125 if (size_32) {
126 uint32_t count_32 = 0;
127 if (!iter.ReadUInt32(&count_32)) {
128 LOG(ERROR) << "Failed to deserialize KWallet entry "
129 << "(realm: " << signon_realm << ")";
130 return false;
131 }
132 count = count_32;
133 } else {
134 if (!iter.ReadSizeT(&count)) {
135 LOG(ERROR) << "Failed to deserialize KWallet entry "
136 << "(realm: " << signon_realm << ")";
137 return false;
138 }
139 }
140
141 if (count > 0xFFFF) {
142 // Trying to pin down the cause of http://crbug.com/80728 (or fix it).
143 // This is a very large number of passwords to be saved for a single realm.
144 // It is almost certainly a corrupt pickle and not real data. Ignore it.
145 // This very well might actually be http://crbug.com/107701, so if we're
146 // reading an old pickle, we don't even log this the first time we try to
147 // read it. (That is, when we're reading the native architecture size.)
148 if (!warn_only) {
149 LOG(ERROR) << "Suspiciously large number of entries in KWallet entry "
150 << "(" << count << "; realm: " << signon_realm << ")";
151 }
152 return false;
153 }
154
155 // We'll swap |converted_forms| with |*forms| on success, to make sure we
156 // don't return partial results on failure.
157 ScopedVector<autofill::PasswordForm> converted_forms;
158 converted_forms.reserve(count);
159 for (size_t i = 0; i < count; ++i) {
160 scoped_ptr<PasswordForm> form(new PasswordForm());
161 form->signon_realm.assign(signon_realm);
162
163 int scheme = 0;
164 int64 date_created = 0;
165 int type = 0;
166 // Note that these will be read back in the order listed due to
167 // short-circuit evaluation. This is important.
168 if (!iter.ReadInt(&scheme) ||
169 !ReadGURL(&iter, warn_only, &form->origin) ||
170 !ReadGURL(&iter, warn_only, &form->action) ||
171 !iter.ReadString16(&form->username_element) ||
172 !iter.ReadString16(&form->username_value) ||
173 !iter.ReadString16(&form->password_element) ||
174 !iter.ReadString16(&form->password_value) ||
175 !iter.ReadString16(&form->submit_element) ||
176 !iter.ReadBool(&form->ssl_valid) ||
177 !iter.ReadBool(&form->preferred) ||
178 !iter.ReadBool(&form->blacklisted_by_user) ||
179 !iter.ReadInt64(&date_created)) {
180 LogDeserializationWarning(version, signon_realm, warn_only);
181 return false;
182 }
183 form->scheme = static_cast<PasswordForm::Scheme>(scheme);
184
185 if (version > 1) {
186 if (!iter.ReadInt(&type) ||
187 !iter.ReadInt(&form->times_used) ||
188 !autofill::DeserializeFormData(&iter, &form->form_data)) {
189 LogDeserializationWarning(version, signon_realm, false);
190 return false;
191 }
192 form->type = static_cast<PasswordForm::Type>(type);
193 }
194
195 if (version > 2) {
196 int64 date_synced = 0;
197 if (!iter.ReadInt64(&date_synced)) {
198 LogDeserializationWarning(version, signon_realm, false);
199 return false;
200 }
201 form->date_synced = base::Time::FromInternalValue(date_synced);
202 }
203
204 if (version > 3) {
205 if (!iter.ReadString16(&form->display_name) ||
206 !ReadGURL(&iter, warn_only, &form->avatar_url) ||
207 !ReadGURL(&iter, warn_only, &form->federation_url) ||
208 !iter.ReadBool(&form->skip_zero_click)) {
209 LogDeserializationWarning(version, signon_realm, false);
210 return false;
211 }
212 }
213
214 if (version > 4) {
215 form->date_created = base::Time::FromInternalValue(date_created);
216 } else {
217 form->date_created = base::Time::FromTimeT(date_created);
218 }
219
220 converted_forms.push_back(form.release());
221 }
222
223 forms->swap(converted_forms);
224 return true;
225 }
226
227 // Serializes a list of PasswordForms to be stored in the wallet.
228 void SerializeValue(const std::vector<autofill::PasswordForm*>& forms,
229 Pickle* pickle) {
230 pickle->WriteInt(kPickleVersion);
231 pickle->WriteSizeT(forms.size());
232 for (autofill::PasswordForm* form : forms) {
233 pickle->WriteInt(form->scheme);
234 pickle->WriteString(form->origin.spec());
235 pickle->WriteString(form->action.spec());
236 pickle->WriteString16(form->username_element);
237 pickle->WriteString16(form->username_value);
238 pickle->WriteString16(form->password_element);
239 pickle->WriteString16(form->password_value);
240 pickle->WriteString16(form->submit_element);
241 pickle->WriteBool(form->ssl_valid);
242 pickle->WriteBool(form->preferred);
243 pickle->WriteBool(form->blacklisted_by_user);
244 pickle->WriteInt64(form->date_created.ToInternalValue());
245 pickle->WriteInt(form->type);
246 pickle->WriteInt(form->times_used);
247 autofill::SerializeFormData(form->form_data, pickle);
248 pickle->WriteInt64(form->date_synced.ToInternalValue());
249 pickle->WriteString16(form->display_name);
250 pickle->WriteString(form->avatar_url.spec());
251 pickle->WriteString(form->federation_url.spec());
252 pickle->WriteBool(form->skip_zero_click);
253 }
254 }
255
256 // Moves the content of |second| to the end of |first|.
257 void AppendSecondToFirst(ScopedVector<autofill::PasswordForm>* first,
258 ScopedVector<autofill::PasswordForm> second) {
259 first->reserve(first->size() + second.size());
260 first->insert(first->end(), second.begin(), second.end());
261 second.weak_clear();
262 }
263
103 } // namespace 264 } // namespace
104 265
105 NativeBackendKWallet::NativeBackendKWallet(LocalProfileId id) 266 NativeBackendKWallet::NativeBackendKWallet(LocalProfileId id)
106 : profile_id_(id), 267 : profile_id_(id),
107 kwallet_proxy_(NULL), 268 kwallet_proxy_(NULL),
108 app_name_(l10n_util::GetStringUTF8(IDS_PRODUCT_NAME)) { 269 app_name_(l10n_util::GetStringUTF8(IDS_PRODUCT_NAME)) {
109 folder_name_ = GetProfileSpecificFolderName(); 270 folder_name_ = GetProfileSpecificFolderName();
110 } 271 }
111 272
112 NativeBackendKWallet::~NativeBackendKWallet() { 273 NativeBackendKWallet::~NativeBackendKWallet() {
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after
375 if (wallet_handle == kInvalidKWalletHandle) 536 if (wallet_handle == kInvalidKWalletHandle)
376 return false; 537 return false;
377 return GetLoginsList(form.signon_realm, wallet_handle, forms); 538 return GetLoginsList(form.signon_realm, wallet_handle, forms);
378 } 539 }
379 540
380 bool NativeBackendKWallet::GetAutofillableLogins( 541 bool NativeBackendKWallet::GetAutofillableLogins(
381 ScopedVector<autofill::PasswordForm>* forms) { 542 ScopedVector<autofill::PasswordForm>* forms) {
382 int wallet_handle = WalletHandle(); 543 int wallet_handle = WalletHandle();
383 if (wallet_handle == kInvalidKWalletHandle) 544 if (wallet_handle == kInvalidKWalletHandle)
384 return false; 545 return false;
385 return GetLoginsList(true, wallet_handle, forms); 546 return GetLoginsList(BlacklistOptions::AUTOFILLABLE, wallet_handle, forms);
386 } 547 }
387 548
388 bool NativeBackendKWallet::GetBlacklistLogins( 549 bool NativeBackendKWallet::GetBlacklistLogins(
389 ScopedVector<autofill::PasswordForm>* forms) { 550 ScopedVector<autofill::PasswordForm>* forms) {
390 int wallet_handle = WalletHandle(); 551 int wallet_handle = WalletHandle();
391 if (wallet_handle == kInvalidKWalletHandle) 552 if (wallet_handle == kInvalidKWalletHandle)
392 return false; 553 return false;
393 return GetLoginsList(false, wallet_handle, forms); 554 return GetLoginsList(BlacklistOptions::BLACKLISTED, wallet_handle, forms);
394 } 555 }
395 556
396 bool NativeBackendKWallet::GetLoginsList( 557 bool NativeBackendKWallet::GetLoginsList(
397 const std::string& signon_realm, 558 const std::string& signon_realm,
398 int wallet_handle, 559 int wallet_handle,
399 ScopedVector<autofill::PasswordForm>* forms) { 560 ScopedVector<autofill::PasswordForm>* forms) {
561 forms->clear();
400 // Is there an entry in the wallet? 562 // Is there an entry in the wallet?
401 { 563 {
402 dbus::MethodCall method_call(kKWalletInterface, "hasEntry"); 564 dbus::MethodCall method_call(kKWalletInterface, "hasEntry");
403 dbus::MessageWriter builder(&method_call); 565 dbus::MessageWriter builder(&method_call);
404 builder.AppendInt32(wallet_handle); // handle 566 builder.AppendInt32(wallet_handle); // handle
405 builder.AppendString(folder_name_); // folder 567 builder.AppendString(folder_name_); // folder
406 builder.AppendString(signon_realm); // key 568 builder.AppendString(signon_realm); // key
407 builder.AppendString(app_name_); // appid 569 builder.AppendString(app_name_); // appid
408 scoped_ptr<dbus::Response> response( 570 scoped_ptr<dbus::Response> response(
409 kwallet_proxy_->CallMethodAndBlock( 571 kwallet_proxy_->CallMethodAndBlock(
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
452 if (!CheckSerializedValue(bytes, length, signon_realm)) { 614 if (!CheckSerializedValue(bytes, length, signon_realm)) {
453 // This is weird, but we choose not to call it an error. There is an 615 // 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 616 // 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 617 // repair without having to delete it using kwalletmanager (that is, by
456 // just saving a new password within this realm to overwrite it). 618 // just saving a new password within this realm to overwrite it).
457 return true; 619 return true;
458 } 620 }
459 621
460 // Can't we all just agree on whether bytes are signed or not? Please? 622 // Can't we all just agree on whether bytes are signed or not? Please?
461 Pickle pickle(reinterpret_cast<const char*>(bytes), length); 623 Pickle pickle(reinterpret_cast<const char*>(bytes), length);
462 DeserializeValue(signon_realm, pickle, forms); 624 *forms = DeserializeValue(signon_realm, pickle);
463 } 625 }
464 626
465 return true; 627 return true;
466 } 628 }
467 629
468 bool NativeBackendKWallet::GetLoginsList( 630 bool NativeBackendKWallet::GetLoginsList(
469 bool autofillable, 631 BlacklistOptions options,
470 int wallet_handle, 632 int wallet_handle,
471 ScopedVector<autofill::PasswordForm>* forms) { 633 ScopedVector<autofill::PasswordForm>* forms) {
634 forms->clear();
472 ScopedVector<autofill::PasswordForm> all_forms; 635 ScopedVector<autofill::PasswordForm> all_forms;
473 if (!GetAllLogins(wallet_handle, &all_forms)) 636 if (!GetAllLogins(wallet_handle, &all_forms))
474 return false; 637 return false;
475 638
476 // We have to read all the entries, and then filter them here. 639 // We have to read all the entries, and then filter them here.
477 forms->reserve(forms->size() + all_forms.size()); 640 forms->reserve(all_forms.size());
478 for (auto& saved_form : all_forms) { 641 for (auto& saved_form : all_forms) {
479 if (saved_form->blacklisted_by_user == !autofillable) { 642 if (saved_form->blacklisted_by_user ==
643 (options == BlacklistOptions::BLACKLISTED)) {
480 forms->push_back(saved_form); 644 forms->push_back(saved_form);
481 saved_form = nullptr; 645 saved_form = nullptr;
482 } 646 }
483 } 647 }
484 648
485 return true; 649 return true;
486 } 650 }
487 651
488 bool NativeBackendKWallet::GetAllLogins( 652 bool NativeBackendKWallet::GetAllLogins(
489 int wallet_handle, 653 int wallet_handle,
490 ScopedVector<autofill::PasswordForm>* forms) { 654 ScopedVector<autofill::PasswordForm>* forms) {
655 forms->clear();
491 // We could probably also use readEntryList here. 656 // We could probably also use readEntryList here.
492 std::vector<std::string> realm_list; 657 std::vector<std::string> realm_list;
493 { 658 {
494 dbus::MethodCall method_call(kKWalletInterface, "entryList"); 659 dbus::MethodCall method_call(kKWalletInterface, "entryList");
495 dbus::MessageWriter builder(&method_call); 660 dbus::MessageWriter builder(&method_call);
496 builder.AppendInt32(wallet_handle); // handle 661 builder.AppendInt32(wallet_handle); // handle
497 builder.AppendString(folder_name_); // folder 662 builder.AppendString(folder_name_); // folder
498 builder.AppendString(app_name_); // appid 663 builder.AppendString(app_name_); // appid
499 scoped_ptr<dbus::Response> response( 664 scoped_ptr<dbus::Response> response(
500 kwallet_proxy_->CallMethodAndBlock( 665 kwallet_proxy_->CallMethodAndBlock(
501 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT)); 666 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
502 if (!response.get()) { 667 if (!response.get()) {
503 LOG(ERROR) << "Error contacting kwalletd (entryList)"; 668 LOG(ERROR) << "Error contacting kwalletd (entryList)";
504 return false; 669 return false;
505 } 670 }
506 dbus::MessageReader reader(response.get()); 671 dbus::MessageReader reader(response.get());
507 if (!reader.PopArrayOfStrings(&realm_list)) { 672 if (!reader.PopArrayOfStrings(&realm_list)) {
508 LOG(ERROR) << "Error reading response from kwalletd (entryList): " 673 LOG(ERROR) << "Error reading response from kwalletd (entryList): "
509 << response->ToString(); 674 << response->ToString();
510 return false; 675 return false;
511 } 676 }
512 } 677 }
513 678
514 for (size_t i = 0; i < realm_list.size(); ++i) { 679 // Swapping |collected_forms| with |*forms| just before "return true" makes
515 const std::string& signon_realm = realm_list[i]; 680 // sure partial results are not returned on failure.
681 ScopedVector<autofill::PasswordForm> collected_forms;
682 for (const std::string& signon_realm : realm_list) {
516 dbus::MethodCall method_call(kKWalletInterface, "readEntry"); 683 dbus::MethodCall method_call(kKWalletInterface, "readEntry");
517 dbus::MessageWriter builder(&method_call); 684 dbus::MessageWriter builder(&method_call);
518 builder.AppendInt32(wallet_handle); // handle 685 builder.AppendInt32(wallet_handle); // handle
519 builder.AppendString(folder_name_); // folder 686 builder.AppendString(folder_name_); // folder
520 builder.AppendString(signon_realm); // key 687 builder.AppendString(signon_realm); // key
521 builder.AppendString(app_name_); // appid 688 builder.AppendString(app_name_); // appid
522 scoped_ptr<dbus::Response> response( 689 scoped_ptr<dbus::Response> response(
523 kwallet_proxy_->CallMethodAndBlock( 690 kwallet_proxy_->CallMethodAndBlock(
524 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT)); 691 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
525 if (!response.get()) { 692 if (!response.get()) {
526 LOG(ERROR) << "Error contacting kwalletd (readEntry)"; 693 LOG(ERROR) << "Error contacting kwalletd (readEntry)";
527 return false; 694 return false;
528 } 695 }
529 dbus::MessageReader reader(response.get()); 696 dbus::MessageReader reader(response.get());
530 const uint8_t* bytes = NULL; 697 const uint8_t* bytes = NULL;
531 size_t length = 0; 698 size_t length = 0;
532 if (!reader.PopArrayOfBytes(&bytes, &length)) { 699 if (!reader.PopArrayOfBytes(&bytes, &length)) {
533 LOG(ERROR) << "Error reading response from kwalletd (readEntry): " 700 LOG(ERROR) << "Error reading response from kwalletd (readEntry): "
534 << response->ToString(); 701 << response->ToString();
535 return false; 702 return false;
536 } 703 }
537 if (!bytes || !CheckSerializedValue(bytes, length, signon_realm)) 704 if (!bytes || !CheckSerializedValue(bytes, length, signon_realm))
538 continue; 705 continue;
539 706
540 // Can't we all just agree on whether bytes are signed or not? Please? 707 // Can't we all just agree on whether bytes are signed or not? Please?
541 Pickle pickle(reinterpret_cast<const char*>(bytes), length); 708 Pickle pickle(reinterpret_cast<const char*>(bytes), length);
542 DeserializeValue(signon_realm, pickle, forms); 709 AppendSecondToFirst(&collected_forms,
710 DeserializeValue(signon_realm, pickle));
543 } 711 }
712 forms->swap(collected_forms);
544 return true; 713 return true;
545 } 714 }
546 715
547 bool NativeBackendKWallet::SetLoginsList( 716 bool NativeBackendKWallet::SetLoginsList(
548 const std::vector<autofill::PasswordForm*>& forms, 717 const std::vector<autofill::PasswordForm*>& forms,
549 const std::string& signon_realm, 718 const std::string& signon_realm,
550 int wallet_handle) { 719 int wallet_handle) {
551 if (forms.empty()) { 720 if (forms.empty()) {
552 // No items left? Remove the entry from the wallet. 721 // No items left? Remove the entry from the wallet.
553 dbus::MethodCall method_call(kKWalletInterface, "removeEntry"); 722 dbus::MethodCall method_call(kKWalletInterface, "removeEntry");
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
669 if (!reader.PopArrayOfBytes(&bytes, &length)) { 838 if (!reader.PopArrayOfBytes(&bytes, &length)) {
670 LOG(ERROR) << "Error reading response from kwalletd (readEntry): " 839 LOG(ERROR) << "Error reading response from kwalletd (readEntry): "
671 << response->ToString(); 840 << response->ToString();
672 continue; 841 continue;
673 } 842 }
674 if (!bytes || !CheckSerializedValue(bytes, length, signon_realm)) 843 if (!bytes || !CheckSerializedValue(bytes, length, signon_realm))
675 continue; 844 continue;
676 845
677 // Can't we all just agree on whether bytes are signed or not? Please? 846 // Can't we all just agree on whether bytes are signed or not? Please?
678 Pickle pickle(reinterpret_cast<const char*>(bytes), length); 847 Pickle pickle(reinterpret_cast<const char*>(bytes), length);
679 ScopedVector<autofill::PasswordForm> all_forms; 848 ScopedVector<autofill::PasswordForm> all_forms =
680 DeserializeValue(signon_realm, pickle, &all_forms); 849 DeserializeValue(signon_realm, pickle);
681 850
682 ScopedVector<autofill::PasswordForm> kept_forms; 851 ScopedVector<autofill::PasswordForm> kept_forms;
683 kept_forms.reserve(all_forms.size()); 852 kept_forms.reserve(all_forms.size());
684 base::Time autofill::PasswordForm::*date_member = 853 base::Time autofill::PasswordForm::*date_member =
685 date_to_compare == CREATION_TIMESTAMP 854 date_to_compare == CREATION_TIMESTAMP
686 ? &autofill::PasswordForm::date_created 855 ? &autofill::PasswordForm::date_created
687 : &autofill::PasswordForm::date_synced; 856 : &autofill::PasswordForm::date_synced;
688 for (auto& saved_form : all_forms) { 857 for (auto& saved_form : all_forms) {
689 if (delete_begin <= saved_form->*date_member && 858 if (delete_begin <= saved_form->*date_member &&
690 (delete_end.is_null() || saved_form->*date_member < delete_end)) { 859 (delete_end.is_null() || saved_form->*date_member < delete_end)) {
691 changes->push_back(password_manager::PasswordStoreChange( 860 changes->push_back(password_manager::PasswordStoreChange(
692 password_manager::PasswordStoreChange::REMOVE, *saved_form)); 861 password_manager::PasswordStoreChange::REMOVE, *saved_form));
693 } else { 862 } else {
694 kept_forms.push_back(saved_form); 863 kept_forms.push_back(saved_form);
695 saved_form = nullptr; 864 saved_form = nullptr;
696 } 865 }
697 } 866 }
698 867
699 if (!SetLoginsList(kept_forms.get(), signon_realm, wallet_handle)) { 868 if (!SetLoginsList(kept_forms.get(), signon_realm, wallet_handle)) {
700 ok = false; 869 ok = false;
701 changes->clear(); 870 changes->clear();
702 } 871 }
703 } 872 }
704 return ok; 873 return ok;
705 } 874 }
706 875
707 // static 876 // static
708 void NativeBackendKWallet::SerializeValue( 877 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 }
735 }
736
737 // static
738 bool NativeBackendKWallet::DeserializeValueSize(
739 const std::string& signon_realm, 878 const std::string& signon_realm,
740 const PickleIterator& init_iter, 879 const Pickle& pickle) {
741 int version,
742 bool size_32,
743 bool warn_only,
744 ScopedVector<autofill::PasswordForm>* forms) {
745 PickleIterator iter = init_iter;
746
747 size_t count = 0;
748 if (size_32) {
749 uint32_t count_32 = 0;
750 if (!iter.ReadUInt32(&count_32)) {
751 LOG(ERROR) << "Failed to deserialize KWallet entry "
752 << "(realm: " << signon_realm << ")";
753 return false;
754 }
755 count = count_32;
756 } else {
757 if (!iter.ReadSizeT(&count)) {
758 LOG(ERROR) << "Failed to deserialize KWallet entry "
759 << "(realm: " << signon_realm << ")";
760 return false;
761 }
762 }
763
764 if (count > 0xFFFF) {
765 // Trying to pin down the cause of http://crbug.com/80728 (or fix it).
766 // This is a very large number of passwords to be saved for a single realm.
767 // It is almost certainly a corrupt pickle and not real data. Ignore it.
768 // This very well might actually be http://crbug.com/107701, so if we're
769 // reading an old pickle, we don't even log this the first time we try to
770 // read it. (That is, when we're reading the native architecture size.)
771 if (!warn_only) {
772 LOG(ERROR) << "Suspiciously large number of entries in KWallet entry "
773 << "(" << count << "; realm: " << signon_realm << ")";
774 }
775 return false;
776 }
777
778 forms->reserve(forms->size() + count);
779 for (size_t i = 0; i < count; ++i) {
780 scoped_ptr<PasswordForm> form(new PasswordForm());
781 form->signon_realm.assign(signon_realm);
782
783 int scheme = 0;
784 int64 date_created = 0;
785 int type = 0;
786 // Note that these will be read back in the order listed due to
787 // short-circuit evaluation. This is important.
788 if (!iter.ReadInt(&scheme) ||
789 !ReadGURL(&iter, warn_only, &form->origin) ||
790 !ReadGURL(&iter, warn_only, &form->action) ||
791 !iter.ReadString16(&form->username_element) ||
792 !iter.ReadString16(&form->username_value) ||
793 !iter.ReadString16(&form->password_element) ||
794 !iter.ReadString16(&form->password_value) ||
795 !iter.ReadString16(&form->submit_element) ||
796 !iter.ReadBool(&form->ssl_valid) ||
797 !iter.ReadBool(&form->preferred) ||
798 !iter.ReadBool(&form->blacklisted_by_user) ||
799 !iter.ReadInt64(&date_created)) {
800 LogDeserializationWarning(version, signon_realm, warn_only);
801 return false;
802 }
803 form->scheme = static_cast<PasswordForm::Scheme>(scheme);
804
805 if (version > 1) {
806 if (!iter.ReadInt(&type) ||
807 !iter.ReadInt(&form->times_used) ||
808 !autofill::DeserializeFormData(&iter, &form->form_data)) {
809 LogDeserializationWarning(version, signon_realm, false);
810 return false;
811 }
812 form->type = static_cast<PasswordForm::Type>(type);
813 }
814
815 if (version > 2) {
816 int64 date_synced = 0;
817 if (!iter.ReadInt64(&date_synced)) {
818 LogDeserializationWarning(version, signon_realm, false);
819 return false;
820 }
821 form->date_synced = base::Time::FromInternalValue(date_synced);
822 }
823
824 if (version > 3) {
825 if (!iter.ReadString16(&form->display_name) ||
826 !ReadGURL(&iter, warn_only, &form->avatar_url) ||
827 !ReadGURL(&iter, warn_only, &form->federation_url) ||
828 !iter.ReadBool(&form->skip_zero_click)) {
829 LogDeserializationWarning(version, signon_realm, false);
830 return false;
831 }
832 }
833
834 if (version > 4) {
835 form->date_created = base::Time::FromInternalValue(date_created);
836 } else {
837 form->date_created = base::Time::FromTimeT(date_created);
838 }
839
840 forms->push_back(form.release());
841 }
842
843 return true;
844 }
845
846 // static
847 void NativeBackendKWallet::DeserializeValue(
848 const std::string& signon_realm,
849 const Pickle& pickle,
850 ScopedVector<autofill::PasswordForm>* forms) {
851 PickleIterator iter(pickle); 880 PickleIterator iter(pickle);
852 881
853 int version = -1; 882 int version = -1;
854 if (!iter.ReadInt(&version) || 883 if (!iter.ReadInt(&version) ||
855 version < 0 || version > kPickleVersion) { 884 version < 0 || version > kPickleVersion) {
856 LOG(ERROR) << "Failed to deserialize KWallet entry " 885 LOG(ERROR) << "Failed to deserialize KWallet entry "
857 << "(realm: " << signon_realm << ")"; 886 << "(realm: " << signon_realm << ")";
858 return; 887 return ScopedVector<autofill::PasswordForm>();
859 } 888 }
860 889
890 ScopedVector<autofill::PasswordForm> forms;
861 if (version > 0) { 891 if (version > 0) {
862 // In current pickles, we expect 64-bit sizes. Failure is an error. 892 // In current pickles, we expect 64-bit sizes. Failure is an error.
863 DeserializeValueSize(signon_realm, iter, version, false, false, forms); 893 DeserializeValueSize(signon_realm, iter, version, false, false, &forms);
864 return; 894 return forms.Pass();
865 } 895 }
866 896
867 const size_t saved_forms_size = forms->size();
868 const bool size_32 = sizeof(size_t) == sizeof(uint32_t); 897 const bool size_32 = sizeof(size_t) == sizeof(uint32_t);
869 if (!DeserializeValueSize( 898 if (!DeserializeValueSize(
870 signon_realm, iter, version, size_32, true, forms)) { 899 signon_realm, iter, version, size_32, true, &forms)) {
871 // We failed to read the pickle using the native architecture of the system. 900 // We failed to read the pickle using the native architecture of the system.
872 // Try again with the opposite architecture. Note that we do this even on 901 // Try again with the opposite architecture. Note that we do this even on
873 // 32-bit machines, in case we're reading a 64-bit pickle. (Probably rare, 902 // 32-bit machines, in case we're reading a 64-bit pickle. (Probably rare,
874 // since mostly we expect upgrades, not downgrades, but both are possible.) 903 // since mostly we expect upgrades, not downgrades, but both are possible.)
875 forms->resize(saved_forms_size); 904 DeserializeValueSize(signon_realm, iter, version, !size_32, false, &forms);
876 DeserializeValueSize(signon_realm, iter, version, !size_32, false, forms);
877 } 905 }
906 return forms.Pass();
878 } 907 }
879 908
880 int NativeBackendKWallet::WalletHandle() { 909 int NativeBackendKWallet::WalletHandle() {
881 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); 910 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
882 911
883 // Open the wallet. 912 // Open the wallet.
884 // TODO(mdm): Are we leaking these handles? Find out. 913 // TODO(mdm): Are we leaking these handles? Find out.
885 int32_t handle = kInvalidKWalletHandle; 914 int32_t handle = kInvalidKWalletHandle;
886 { 915 {
887 dbus::MethodCall method_call(kKWalletInterface, "open"); 916 dbus::MethodCall method_call(kKWalletInterface, "open");
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
959 } 988 }
960 989
961 return handle; 990 return handle;
962 } 991 }
963 992
964 std::string NativeBackendKWallet::GetProfileSpecificFolderName() const { 993 std::string NativeBackendKWallet::GetProfileSpecificFolderName() const {
965 // Originally, the folder name was always just "Chrome Form Data". 994 // Originally, the folder name was always just "Chrome Form Data".
966 // Now we use it to distinguish passwords for different profiles. 995 // Now we use it to distinguish passwords for different profiles.
967 return base::StringPrintf("%s (%d)", kKWalletFolder, profile_id_); 996 return base::StringPrintf("%s (%d)", kKWalletFolder, profile_id_);
968 } 997 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698