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

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

Issue 2318303002: Remove stl_util's STLDeleteContainerPairSecondPointers. (Closed)
Patch Set: fix Created 4 years, 3 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/password_store_mac.h" 5 #include "chrome/browser/password_manager/password_store_mac.h"
6 6
7 #include <CoreServices/CoreServices.h> 7 #include <CoreServices/CoreServices.h>
8 #include <stddef.h> 8 #include <stddef.h>
9 #include <algorithm> 9 #include <algorithm>
10 #include <set> 10 #include <set>
11 #include <string> 11 #include <string>
12 #include <utility> 12 #include <utility>
13 #include <vector> 13 #include <vector>
14 14
15 #include "base/callback.h" 15 #include "base/callback.h"
16 #include "base/logging.h" 16 #include "base/logging.h"
17 #include "base/mac/foundation_util.h" 17 #include "base/mac/foundation_util.h"
18 #include "base/mac/mac_logging.h" 18 #include "base/mac/mac_logging.h"
19 #include "base/macros.h" 19 #include "base/macros.h"
20 #include "base/memory/ptr_util.h"
20 #include "base/message_loop/message_loop.h" 21 #include "base/message_loop/message_loop.h"
21 #include "base/metrics/histogram_macros.h" 22 #include "base/metrics/histogram_macros.h"
22 #include "base/stl_util.h"
23 #include "base/strings/string_util.h" 23 #include "base/strings/string_util.h"
24 #include "base/strings/utf_string_conversions.h" 24 #include "base/strings/utf_string_conversions.h"
25 #include "chrome/browser/mac/security_wrappers.h" 25 #include "chrome/browser/mac/security_wrappers.h"
26 #include "chrome/browser/password_manager/password_store_mac_internal.h" 26 #include "chrome/browser/password_manager/password_store_mac_internal.h"
27 #include "components/os_crypt/os_crypt.h" 27 #include "components/os_crypt/os_crypt.h"
28 #include "components/password_manager/core/browser/affiliation_utils.h" 28 #include "components/password_manager/core/browser/affiliation_utils.h"
29 #include "components/password_manager/core/browser/login_database.h" 29 #include "components/password_manager/core/browser/login_database.h"
30 #include "components/password_manager/core/browser/password_manager_util.h" 30 #include "components/password_manager/core/browser/password_manager_util.h"
31 #include "components/password_manager/core/browser/password_store_change.h" 31 #include "components/password_manager/core/browser/password_store_change.h"
32 #include "content/public/browser/browser_thread.h" 32 #include "content/public/browser/browser_thread.h"
33 #include "crypto/apple_keychain.h" 33 #include "crypto/apple_keychain.h"
34 #include "url/origin.h" 34 #include "url/origin.h"
35 35
36 using autofill::PasswordForm; 36 using autofill::PasswordForm;
37 using crypto::AppleKeychain; 37 using crypto::AppleKeychain;
38 using password_manager::PasswordStoreChange; 38 using password_manager::PasswordStoreChange;
39 using password_manager::PasswordStoreChangeList; 39 using password_manager::PasswordStoreChangeList;
40 40
41 namespace { 41 namespace {
42 42
43 // Utility class to handle the details of constructing and running a keychain 43 // Utility class to handle the details of constructing and running a keychain
44 // search from a set of attributes. 44 // search from a set of attributes.
45 class KeychainSearch { 45 class KeychainSearch {
46 public: 46 public:
47 explicit KeychainSearch(const AppleKeychain& keychain); 47 explicit KeychainSearch(const AppleKeychain& keychain);
48 ~KeychainSearch(); 48 ~KeychainSearch();
49 49
50 // Sets up a keycahin search based on an non "null" (NULL for char*, 50 // Sets up a keychain search based on an non "null" (NULL for char*,
51 // The appropriate "Any" entry for other types) arguments. 51 // The appropriate "Any" entry for other types) arguments.
52 // 52 //
53 // IMPORTANT: Any paramaters passed in *must* remain valid for as long as the 53 // IMPORTANT: Any parameters passed in *must* remain valid for as long as the
54 // KeychainSearch object, since the search uses them by reference. 54 // KeychainSearch object, since the search uses them by reference.
55 void Init(const char* server, 55 void Init(const char* server,
56 const UInt32* port, 56 const UInt32* port,
57 const SecProtocolType* protocol, 57 const SecProtocolType* protocol,
58 const SecAuthenticationType* auth_type, 58 const SecAuthenticationType* auth_type,
59 const char* security_domain, 59 const char* security_domain,
60 const char* path, 60 const char* path,
61 const char* username, 61 const char* username,
62 const OSType* creator); 62 const OSType* creator);
63 63
(...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after
318 PasswordForm::Scheme SchemeForAuthType(SecAuthenticationType auth_type) { 318 PasswordForm::Scheme SchemeForAuthType(SecAuthenticationType auth_type) {
319 switch (auth_type) { 319 switch (auth_type) {
320 case kSecAuthenticationTypeHTMLForm: return PasswordForm::SCHEME_HTML; 320 case kSecAuthenticationTypeHTMLForm: return PasswordForm::SCHEME_HTML;
321 case kSecAuthenticationTypeHTTPBasic: return PasswordForm::SCHEME_BASIC; 321 case kSecAuthenticationTypeHTTPBasic: return PasswordForm::SCHEME_BASIC;
322 case kSecAuthenticationTypeHTTPDigest: return PasswordForm::SCHEME_DIGEST; 322 case kSecAuthenticationTypeHTTPDigest: return PasswordForm::SCHEME_DIGEST;
323 default: return PasswordForm::SCHEME_OTHER; 323 default: return PasswordForm::SCHEME_OTHER;
324 } 324 }
325 } 325 }
326 326
327 bool FillPasswordFormFromKeychainItem(const AppleKeychain& keychain, 327 bool FillPasswordFormFromKeychainItem(const AppleKeychain& keychain,
328 const SecKeychainItemRef& keychain_item, 328 SecKeychainItemRef keychain_item,
329 PasswordForm* form, 329 PasswordForm* form,
330 bool extract_password_data) { 330 bool extract_password_data) {
331 DCHECK(form); 331 DCHECK(form);
332 332
333 SecKeychainAttributeInfo attrInfo; 333 SecKeychainAttributeInfo attrInfo;
334 UInt32 tags[] = { kSecAccountItemAttr, 334 UInt32 tags[] = { kSecAccountItemAttr,
335 kSecServerItemAttr, 335 kSecServerItemAttr,
336 kSecPortItemAttr, 336 kSecPortItemAttr,
337 kSecPathItemAttr, 337 kSecPathItemAttr,
338 kSecProtocolItemAttr, 338 kSecProtocolItemAttr,
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
450 // format. 450 // format.
451 form->signon_realm = form->origin.GetOrigin().spec(); 451 form->signon_realm = form->origin.GetOrigin().spec();
452 if (form->scheme != PasswordForm::SCHEME_HTML) { 452 if (form->scheme != PasswordForm::SCHEME_HTML) {
453 form->signon_realm.append(security_domain); 453 form->signon_realm.append(security_domain);
454 } 454 }
455 } 455 }
456 return true; 456 return true;
457 } 457 }
458 458
459 bool HasChromeCreatorCode(const AppleKeychain& keychain, 459 bool HasChromeCreatorCode(const AppleKeychain& keychain,
460 const SecKeychainItemRef& keychain_item) { 460 SecKeychainItemRef keychain_item) {
461 SecKeychainAttributeInfo attr_info; 461 SecKeychainAttributeInfo attr_info;
462 UInt32 tags[] = {kSecCreatorItemAttr}; 462 UInt32 tags[] = {kSecCreatorItemAttr};
463 attr_info.count = arraysize(tags); 463 attr_info.count = arraysize(tags);
464 attr_info.tag = tags; 464 attr_info.tag = tags;
465 attr_info.format = nullptr; 465 attr_info.format = nullptr;
466 466
467 SecKeychainAttributeList* attr_list; 467 SecKeychainAttributeList* attr_list;
468 UInt32 password_length; 468 UInt32 password_length;
469 OSStatus result = keychain.ItemCopyAttributesAndData( 469 OSStatus result = keychain.ItemCopyAttributesAndData(
470 keychain_item, &attr_info, nullptr, &attr_list, 470 keychain_item, &attr_info, nullptr, &attr_list,
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
569 keychain_forms->swap(unused_keychain_forms); 569 keychain_forms->swap(unused_keychain_forms);
570 } 570 }
571 571
572 std::vector<ItemFormPair> ExtractAllKeychainItemAttributesIntoPasswordForms( 572 std::vector<ItemFormPair> ExtractAllKeychainItemAttributesIntoPasswordForms(
573 std::vector<SecKeychainItemRef>* keychain_items, 573 std::vector<SecKeychainItemRef>* keychain_items,
574 const AppleKeychain& keychain) { 574 const AppleKeychain& keychain) {
575 DCHECK(keychain_items); 575 DCHECK(keychain_items);
576 MacKeychainPasswordFormAdapter keychain_adapter(&keychain); 576 MacKeychainPasswordFormAdapter keychain_adapter(&keychain);
577 *keychain_items = keychain_adapter.GetAllPasswordFormKeychainItems(); 577 *keychain_items = keychain_adapter.GetAllPasswordFormKeychainItems();
578 std::vector<ItemFormPair> item_form_pairs; 578 std::vector<ItemFormPair> item_form_pairs;
579 for (std::vector<SecKeychainItemRef>::iterator i = keychain_items->begin(); 579 for (const auto& keychain_item : *keychain_items) {
580 i != keychain_items->end(); ++i) { 580 std::unique_ptr<PasswordForm> form_without_password =
581 PasswordForm* form_without_password = new PasswordForm(); 581 base::MakeUnique<PasswordForm>();
582 internal_keychain_helpers::FillPasswordFormFromKeychainItem( 582 internal_keychain_helpers::FillPasswordFormFromKeychainItem(
583 keychain, 583 keychain, keychain_item, form_without_password.get(),
584 *i,
585 form_without_password,
586 false); // Load password attributes, but not password data. 584 false); // Load password attributes, but not password data.
587 item_form_pairs.push_back(std::make_pair(&(*i), form_without_password)); 585 item_form_pairs.push_back(
586 std::make_pair(keychain_item, std::move(form_without_password)));
588 } 587 }
589 return item_form_pairs; 588 return item_form_pairs;
590 } 589 }
591 590
592 void GetPasswordsForForms(const AppleKeychain& keychain, 591 void GetPasswordsForForms(const AppleKeychain& keychain,
593 ScopedVector<autofill::PasswordForm>* database_forms, 592 ScopedVector<autofill::PasswordForm>* database_forms,
594 ScopedVector<autofill::PasswordForm>* passwords) { 593 ScopedVector<autofill::PasswordForm>* passwords) {
595 // First load the attributes of all items in the keychain without loading 594 // First load the attributes of all items in the keychain without loading
596 // their password data, and then match items in |database_forms| against them. 595 // their password data, and then match items in |database_forms| against them.
597 // This avoids individually searching through the keychain for passwords 596 // This avoids individually searching through the keychain for passwords
(...skipping 20 matching lines...) Expand all
618 ScopedVector<autofill::PasswordForm> keychain_matches = 617 ScopedVector<autofill::PasswordForm> keychain_matches =
619 ExtractPasswordsMergeableWithForm(keychain, item_form_pairs, *form); 618 ExtractPasswordsMergeableWithForm(keychain, item_form_pairs, *form);
620 619
621 ScopedVector<autofill::PasswordForm> db_form_container; 620 ScopedVector<autofill::PasswordForm> db_form_container;
622 db_form_container.push_back(std::move(form)); 621 db_form_container.push_back(std::move(form));
623 MergePasswordForms(&keychain_matches, &db_form_container, passwords); 622 MergePasswordForms(&keychain_matches, &db_form_container, passwords);
624 AppendSecondToFirst(&unused_db_forms, &db_form_container); 623 AppendSecondToFirst(&unused_db_forms, &db_form_container);
625 }); 624 });
626 database_forms->swap(unused_db_forms); 625 database_forms->swap(unused_db_forms);
627 626
628 base::STLDeleteContainerPairSecondPointers(item_form_pairs.begin(),
629 item_form_pairs.end());
630 for (SecKeychainItemRef item : keychain_items) { 627 for (SecKeychainItemRef item : keychain_items) {
631 keychain.Free(item); 628 keychain.Free(item);
632 } 629 }
633 } 630 }
634 631
635 // TODO(stuartmorgan): signon_realm for proxies is not yet supported. 632 // TODO(stuartmorgan): signon_realm for proxies is not yet supported.
636 bool ExtractSignonRealmComponents(const std::string& signon_realm, 633 bool ExtractSignonRealmComponents(const std::string& signon_realm,
637 std::string* server, 634 std::string* server,
638 UInt32* port, 635 UInt32* port,
639 bool* is_secure, 636 bool* is_secure,
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
692 const std::vector<ItemFormPair>& item_form_pairs, 689 const std::vector<ItemFormPair>& item_form_pairs,
693 const PasswordForm& query_form) { 690 const PasswordForm& query_form) {
694 ScopedVector<autofill::PasswordForm> matches; 691 ScopedVector<autofill::PasswordForm> matches;
695 for (std::vector<ItemFormPair>::const_iterator i = item_form_pairs.begin(); 692 for (std::vector<ItemFormPair>::const_iterator i = item_form_pairs.begin();
696 i != item_form_pairs.end(); ++i) { 693 i != item_form_pairs.end(); ++i) {
697 if (FormIsValidAndMatchesOtherForm(query_form, *(i->second))) { 694 if (FormIsValidAndMatchesOtherForm(query_form, *(i->second))) {
698 // Create a new object, since the caller is responsible for deleting the 695 // Create a new object, since the caller is responsible for deleting the
699 // returned forms. 696 // returned forms.
700 std::unique_ptr<PasswordForm> form_with_password(new PasswordForm()); 697 std::unique_ptr<PasswordForm> form_with_password(new PasswordForm());
701 FillPasswordFormFromKeychainItem( 698 FillPasswordFormFromKeychainItem(
702 keychain, *(i->first), form_with_password.get(), 699 keychain, i->first, form_with_password.get(),
703 true); // Load password attributes and data. 700 true); // Load password attributes and data.
704 // Do not include blacklisted items found in the keychain. 701 // Do not include blacklisted items found in the keychain.
705 if (!form_with_password->blacklisted_by_user) 702 if (!form_with_password->blacklisted_by_user)
706 matches.push_back(std::move(form_with_password)); 703 matches.push_back(std::move(form_with_password));
707 } 704 }
708 } 705 }
709 return matches; 706 return matches;
710 } 707 }
711 708
712 } // namespace internal_keychain_helpers 709 } // namespace internal_keychain_helpers
(...skipping 25 matching lines...) Expand all
738 } 735 }
739 736
740 bool MacKeychainPasswordFormAdapter::HasPasswordsMergeableWithForm( 737 bool MacKeychainPasswordFormAdapter::HasPasswordsMergeableWithForm(
741 const PasswordForm& query_form) { 738 const PasswordForm& query_form) {
742 if (IsLoginDatabaseOnlyForm(query_form)) 739 if (IsLoginDatabaseOnlyForm(query_form))
743 return false; 740 return false;
744 std::string username = base::UTF16ToUTF8(query_form.username_value); 741 std::string username = base::UTF16ToUTF8(query_form.username_value);
745 std::vector<SecKeychainItemRef> matches = 742 std::vector<SecKeychainItemRef> matches =
746 MatchingKeychainItems(query_form.signon_realm, query_form.scheme, 743 MatchingKeychainItems(query_form.signon_realm, query_form.scheme,
747 NULL, username.c_str()); 744 NULL, username.c_str());
748 for (std::vector<SecKeychainItemRef>::iterator i = matches.begin(); 745 for (SecKeychainItemRef item : matches)
749 i != matches.end(); ++i) { 746 keychain_->Free(item);
750 keychain_->Free(*i);
751 }
752 747
753 return !matches.empty(); 748 return !matches.empty();
754 } 749 }
755 750
756 std::vector<SecKeychainItemRef> 751 std::vector<SecKeychainItemRef>
757 MacKeychainPasswordFormAdapter::GetAllPasswordFormKeychainItems() { 752 MacKeychainPasswordFormAdapter::GetAllPasswordFormKeychainItems() {
758 SecAuthenticationType supported_auth_types[] = { 753 SecAuthenticationType supported_auth_types[] = {
759 kSecAuthenticationTypeHTMLForm, 754 kSecAuthenticationTypeHTMLForm,
760 kSecAuthenticationTypeHTTPBasic, 755 kSecAuthenticationTypeHTTPBasic,
761 kSecAuthenticationTypeHTTPDigest, 756 kSecAuthenticationTypeHTTPDigest,
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
873 // Path doesn't make sense for Android app credentials. 868 // Path doesn't make sense for Android app credentials.
874 if (!password_manager::IsValidAndroidFacetURI(form.signon_realm)) 869 if (!password_manager::IsValidAndroidFacetURI(form.signon_realm))
875 path = form.origin.path(); 870 path = form.origin.path();
876 std::string username = base::UTF16ToUTF8(form.username_value); 871 std::string username = base::UTF16ToUTF8(form.username_value);
877 std::vector<SecKeychainItemRef> matches = MatchingKeychainItems( 872 std::vector<SecKeychainItemRef> matches = MatchingKeychainItems(
878 form.signon_realm, form.scheme, path.c_str(), username.c_str()); 873 form.signon_realm, form.scheme, path.c_str(), username.c_str());
879 874
880 if (matches.empty()) { 875 if (matches.empty()) {
881 return NULL; 876 return NULL;
882 } 877 }
878
883 // Free all items after the first, since we won't be returning them. 879 // Free all items after the first, since we won't be returning them.
884 for (std::vector<SecKeychainItemRef>::iterator i = matches.begin() + 1; 880 for (auto i = matches.begin() + 1; i != matches.end(); ++i)
885 i != matches.end(); ++i) {
886 keychain_->Free(*i); 881 keychain_->Free(*i);
887 } 882
888 return matches[0]; 883 return matches[0];
889 } 884 }
890 885
891 std::vector<SecKeychainItemRef> 886 std::vector<SecKeychainItemRef>
892 MacKeychainPasswordFormAdapter::MatchingKeychainItems( 887 MacKeychainPasswordFormAdapter::MatchingKeychainItems(
893 const std::string& signon_realm, 888 const std::string& signon_realm,
894 autofill::PasswordForm::Scheme scheme, 889 autofill::PasswordForm::Scheme scheme,
895 const char* path, const char* username) { 890 const char* path, const char* username) {
896 std::vector<SecKeychainItemRef> matches; 891 std::vector<SecKeychainItemRef> matches;
897 892
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
935 case PasswordForm::SCHEME_OTHER: return kSecAuthenticationTypeDefault; 930 case PasswordForm::SCHEME_OTHER: return kSecAuthenticationTypeDefault;
936 case PasswordForm::SCHEME_USERNAME_ONLY: 931 case PasswordForm::SCHEME_USERNAME_ONLY:
937 NOTREACHED(); 932 NOTREACHED();
938 break; 933 break;
939 } 934 }
940 NOTREACHED(); 935 NOTREACHED();
941 return kSecAuthenticationTypeDefault; 936 return kSecAuthenticationTypeDefault;
942 } 937 }
943 938
944 bool MacKeychainPasswordFormAdapter::SetKeychainItemPassword( 939 bool MacKeychainPasswordFormAdapter::SetKeychainItemPassword(
945 const SecKeychainItemRef& keychain_item, const std::string& password) { 940 SecKeychainItemRef keychain_item,
941 const std::string& password) {
946 OSStatus result = keychain_->ItemModifyAttributesAndData(keychain_item, NULL, 942 OSStatus result = keychain_->ItemModifyAttributesAndData(keychain_item, NULL,
947 password.size(), 943 password.size(),
948 password.c_str()); 944 password.c_str());
949 return result == noErr; 945 return result == noErr;
950 } 946 }
951 947
952 bool MacKeychainPasswordFormAdapter::SetKeychainItemCreatorCode( 948 bool MacKeychainPasswordFormAdapter::SetKeychainItemCreatorCode(
953 const SecKeychainItemRef& keychain_item, OSType creator_code) { 949 SecKeychainItemRef keychain_item,
950 OSType creator_code) {
954 SecKeychainAttribute attr = { kSecCreatorItemAttr, sizeof(creator_code), 951 SecKeychainAttribute attr = { kSecCreatorItemAttr, sizeof(creator_code),
955 &creator_code }; 952 &creator_code };
956 SecKeychainAttributeList attrList = { 1, &attr }; 953 SecKeychainAttributeList attrList = { 1, &attr };
957 OSStatus result = keychain_->ItemModifyAttributesAndData(keychain_item, 954 OSStatus result = keychain_->ItemModifyAttributesAndData(keychain_item,
958 &attrList, 0, NULL); 955 &attrList, 0, NULL);
959 return result == noErr; 956 return result == noErr;
960 } 957 }
961 958
962 OSType MacKeychainPasswordFormAdapter::CreatorCodeForSearch() { 959 OSType MacKeychainPasswordFormAdapter::CreatorCodeForSearch() {
963 return finds_only_owned_ ? base::mac::CreatorCodeForApplication() : 0; 960 return finds_only_owned_ ? base::mac::CreatorCodeForApplication() : 0;
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
1033 if (best_match) { 1030 if (best_match) {
1034 form->password_value = best_match->password_value; 1031 form->password_value = best_match->password_value;
1035 PasswordStoreChangeList change = login_db->UpdateLogin(*form); 1032 PasswordStoreChangeList change = login_db->UpdateLogin(*form);
1036 DCHECK_EQ(1u, change.size()); 1033 DCHECK_EQ(1u, change.size());
1037 } else { 1034 } else {
1038 unmerged_forms_count++; 1035 unmerged_forms_count++;
1039 bool removed = login_db->RemoveLogin(*form); 1036 bool removed = login_db->RemoveLogin(*form);
1040 DCHECK(removed); 1037 DCHECK(removed);
1041 } 1038 }
1042 } 1039 }
1043 base::STLDeleteContainerPairSecondPointers(item_form_pairs.begin(),
1044 item_form_pairs.end());
1045 for (SecKeychainItemRef item : keychain_items) 1040 for (SecKeychainItemRef item : keychain_items)
1046 keychain->Free(item); 1041 keychain->Free(item);
1047 1042
1048 if (unmerged_forms_count) { 1043 if (unmerged_forms_count) {
1049 UMA_HISTOGRAM_COUNTS( 1044 UMA_HISTOGRAM_COUNTS(
1050 "PasswordManager.KeychainMigration.NumPasswordsOnFailure", 1045 "PasswordManager.KeychainMigration.NumPasswordsOnFailure",
1051 database_forms.size()); 1046 database_forms.size());
1052 UMA_HISTOGRAM_COUNTS("PasswordManager.KeychainMigration.NumFailedPasswords", 1047 UMA_HISTOGRAM_COUNTS("PasswordManager.KeychainMigration.NumFailedPasswords",
1053 unmerged_forms_count); 1048 unmerged_forms_count);
1054 return MIGRATION_PARTIAL; 1049 return MIGRATION_PARTIAL;
(...skipping 370 matching lines...) Expand 10 before | Expand all | Expand 10 after
1425 ScopedVector<PasswordForm> forms_with_keychain_entry; 1420 ScopedVector<PasswordForm> forms_with_keychain_entry;
1426 internal_keychain_helpers::GetPasswordsForForms(*keychain_, &database_forms, 1421 internal_keychain_helpers::GetPasswordsForForms(*keychain_, &database_forms,
1427 &forms_with_keychain_entry); 1422 &forms_with_keychain_entry);
1428 1423
1429 // Clean up any orphaned database entries. 1424 // Clean up any orphaned database entries.
1430 RemoveDatabaseForms(&database_forms); 1425 RemoveDatabaseForms(&database_forms);
1431 1426
1432 // Move the orphaned DB forms to the output parameter. 1427 // Move the orphaned DB forms to the output parameter.
1433 AppendSecondToFirst(orphaned_forms, &database_forms); 1428 AppendSecondToFirst(orphaned_forms, &database_forms);
1434 } 1429 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698