| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 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 #include "chrome/browser/password_manager/password_store_mac_internal.h" | 6 #include "chrome/browser/password_manager/password_store_mac_internal.h" |
| 7 | 7 |
| 8 #include <CoreServices/CoreServices.h> | 8 #include <CoreServices/CoreServices.h> |
| 9 #include <string> | 9 #include <string> |
| 10 #include <vector> | 10 #include <vector> |
| 11 | 11 |
| 12 #include "base/logging.h" | 12 #include "base/logging.h" |
| 13 #include "base/mac_util.h" | 13 #include "base/mac_util.h" |
| 14 #include "base/stl_util-inl.h" | 14 #include "base/stl_util-inl.h" |
| 15 #include "base/string_util.h" | 15 #include "base/string_util.h" |
| 16 #include "base/task.h" | |
| 17 #include "base/utf_string_conversions.h" | 16 #include "base/utf_string_conversions.h" |
| 18 #include "chrome/browser/keychain_mac.h" | 17 #include "chrome/browser/keychain_mac.h" |
| 19 #include "chrome/browser/password_manager/login_database.h" | 18 #include "chrome/browser/password_manager/login_database.h" |
| 20 #include "chrome/browser/password_manager/password_store_change.h" | |
| 21 | 19 |
| 22 using webkit_glue::PasswordForm; | 20 using webkit_glue::PasswordForm; |
| 23 | 21 |
| 24 // Utility class to handle the details of constructing and running a keychain | 22 // Utility class to handle the details of constructing and running a keychain |
| 25 // search from a set of attributes. | 23 // search from a set of attributes. |
| 26 class KeychainSearch { | 24 class KeychainSearch { |
| 27 public: | 25 public: |
| 28 explicit KeychainSearch(const MacKeychain& keychain); | 26 explicit KeychainSearch(const MacKeychain& keychain); |
| 29 ~KeychainSearch(); | 27 ~KeychainSearch(); |
| 30 | 28 |
| (...skipping 680 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 711 #pragma mark - | 709 #pragma mark - |
| 712 | 710 |
| 713 PasswordStoreMac::PasswordStoreMac(MacKeychain* keychain, | 711 PasswordStoreMac::PasswordStoreMac(MacKeychain* keychain, |
| 714 LoginDatabase* login_db) | 712 LoginDatabase* login_db) |
| 715 : keychain_(keychain), login_metadata_db_(login_db) { | 713 : keychain_(keychain), login_metadata_db_(login_db) { |
| 716 DCHECK(keychain_.get()); | 714 DCHECK(keychain_.get()); |
| 717 DCHECK(login_metadata_db_.get()); | 715 DCHECK(login_metadata_db_.get()); |
| 718 } | 716 } |
| 719 | 717 |
| 720 PasswordStoreMac::~PasswordStoreMac() { | 718 PasswordStoreMac::~PasswordStoreMac() { |
| 721 if (thread_.get()) { | |
| 722 thread_->message_loop()->DeleteSoon(FROM_HERE, | |
| 723 notification_service_.release()); | |
| 724 thread_->message_loop()->RunAllPending(); | |
| 725 } | |
| 726 } | 719 } |
| 727 | 720 |
| 728 bool PasswordStoreMac::Init() { | 721 bool PasswordStoreMac::Init() { |
| 729 thread_.reset(new base::Thread("Chrome_PasswordStore_Thread")); | 722 thread_.reset(new base::Thread("Chrome_PasswordStore_Thread")); |
| 730 | 723 |
| 731 if (!thread_->Start()) { | 724 if (!thread_->Start()) { |
| 732 thread_.reset(NULL); | 725 thread_.reset(NULL); |
| 733 return false; | 726 return false; |
| 734 } | 727 } |
| 735 ScheduleTask(NewRunnableMethod(this, | |
| 736 &PasswordStoreMac::CreateNotificationService)); | |
| 737 return PasswordStore::Init(); | 728 return PasswordStore::Init(); |
| 738 } | 729 } |
| 739 | 730 |
| 740 void PasswordStoreMac::ScheduleTask(Task* task) { | 731 void PasswordStoreMac::ScheduleTask(Task* task) { |
| 741 if (thread_.get()) { | 732 if (thread_.get()) { |
| 742 thread_->message_loop()->PostTask(FROM_HERE, task); | 733 thread_->message_loop()->PostTask(FROM_HERE, task); |
| 743 } | 734 } |
| 744 } | 735 } |
| 745 | 736 |
| 746 void PasswordStoreMac::AddLoginImpl(const PasswordForm& form) { | 737 void PasswordStoreMac::AddLoginImpl(const PasswordForm& form) { |
| 747 if (AddToKeychainIfNecessary(form)) { | 738 if (AddToKeychainIfNecessary(form)) { |
| 748 if (login_metadata_db_->AddLogin(form)) { | 739 login_metadata_db_->AddLogin(form); |
| 749 PasswordStoreChangeList changes; | |
| 750 changes.push_back(PasswordStoreChange(PasswordStoreChange::ADD, form)); | |
| 751 NotificationService::current()->Notify( | |
| 752 NotificationType::LOGINS_CHANGED, | |
| 753 NotificationService::AllSources(), | |
| 754 Details<PasswordStoreChangeList>(&changes)); | |
| 755 } | |
| 756 } | 740 } |
| 757 } | 741 } |
| 758 | 742 |
| 759 void PasswordStoreMac::UpdateLoginImpl(const PasswordForm& form) { | 743 void PasswordStoreMac::UpdateLoginImpl(const PasswordForm& form) { |
| 760 // The keychain add will update if there is a collision and add if there | 744 // The keychain add will update if there is a collision and add if there |
| 761 // isn't, which is the behavior we want, so there's no separate update call. | 745 // isn't, which is the behavior we want, so there's no separate update call. |
| 762 if (AddToKeychainIfNecessary(form)) { | 746 if (AddToKeychainIfNecessary(form)) { |
| 763 int update_count = 0; | 747 int update_count = 0; |
| 764 if (login_metadata_db_->UpdateLogin(form, &update_count)) { | 748 login_metadata_db_->UpdateLogin(form, &update_count); |
| 765 // Update will catch any database entries that we already had, but we | 749 // Update will catch any database entries that we already had, but we could |
| 766 // could also be updating a keychain-only form, in which case we need to | 750 // also be updating a keychain-only form, in which case we need to add. |
| 767 // add. | 751 if (update_count == 0) { |
| 768 PasswordStoreChangeList changes; | 752 login_metadata_db_->AddLogin(form); |
| 769 if (update_count == 0) { | |
| 770 if (login_metadata_db_->AddLogin(form)) { | |
| 771 changes.push_back(PasswordStoreChange(PasswordStoreChange::ADD, | |
| 772 form)); | |
| 773 } | |
| 774 } else { | |
| 775 changes.push_back(PasswordStoreChange(PasswordStoreChange::UPDATE, | |
| 776 form)); | |
| 777 } | |
| 778 if (!changes.empty()) { | |
| 779 NotificationService::current()->Notify( | |
| 780 NotificationType::LOGINS_CHANGED, | |
| 781 NotificationService::AllSources(), | |
| 782 Details<PasswordStoreChangeList>(&changes)); | |
| 783 } | |
| 784 } | 753 } |
| 785 } | 754 } |
| 786 } | 755 } |
| 787 | 756 |
| 788 void PasswordStoreMac::RemoveLoginImpl(const PasswordForm& form) { | 757 void PasswordStoreMac::RemoveLoginImpl(const PasswordForm& form) { |
| 789 if (login_metadata_db_->RemoveLogin(form)) { | 758 login_metadata_db_->RemoveLogin(form); |
| 790 // See if we own a Keychain item associated with this item. We can do an | 759 |
| 791 // exact search rather than messing around with trying to do fuzzy matching | 760 // See if we own a Keychain item associated with this item. We can do an exact |
| 792 // because passwords that we created will always have an exact-match | 761 // search rather than messing around with trying to do fuzzy matching because |
| 793 // database entry. | 762 // passwords that we created will always have an exact-match database entry. |
| 794 // (If a user does lose their profile but not their keychain we'll treat the | 763 // (If a user does lose their profile but not their keychain we'll treat the |
| 795 // entries we find like other imported entries anyway, so it's reasonable to | 764 // entries we find like other imported entries anyway, so it's reasonable to |
| 796 // handle deletes on them the way we would for an imported item.) | 765 // handle deletes on them the way we would for an imported item.) |
| 797 MacKeychainPasswordFormAdapter owned_keychain_adapter(keychain_.get()); | 766 MacKeychainPasswordFormAdapter owned_keychain_adapter(keychain_.get()); |
| 798 owned_keychain_adapter.SetFindsOnlyOwnedItems(true); | 767 owned_keychain_adapter.SetFindsOnlyOwnedItems(true); |
| 799 PasswordForm* owned_password_form = | 768 PasswordForm* owned_password_form = |
| 800 owned_keychain_adapter.PasswordExactlyMatchingForm(form); | 769 owned_keychain_adapter.PasswordExactlyMatchingForm(form); |
| 801 if (owned_password_form) { | 770 if (owned_password_form) { |
| 802 // If we don't have other forms using it (i.e., a form differing only by | 771 // If we don't have other forms using it (i.e., a form differing only by |
| 803 // the names of the form elements), delete the keychain entry. | 772 // the names of the form elements), delete the keychain entry. |
| 804 if (!DatabaseHasFormMatchingKeychainForm(form)) { | 773 if (!DatabaseHasFormMatchingKeychainForm(form)) { |
| 805 owned_keychain_adapter.RemovePassword(form); | 774 owned_keychain_adapter.RemovePassword(form); |
| 806 } | |
| 807 } | 775 } |
| 808 | |
| 809 PasswordStoreChangeList changes; | |
| 810 changes.push_back(PasswordStoreChange(PasswordStoreChange::REMOVE, form)); | |
| 811 NotificationService::current()->Notify( | |
| 812 NotificationType::LOGINS_CHANGED, | |
| 813 NotificationService::AllSources(), | |
| 814 Details<PasswordStoreChangeList>(&changes)); | |
| 815 } | 776 } |
| 816 } | 777 } |
| 817 | 778 |
| 818 void PasswordStoreMac::RemoveLoginsCreatedBetweenImpl( | 779 void PasswordStoreMac::RemoveLoginsCreatedBetweenImpl( |
| 819 const base::Time& delete_begin, const base::Time& delete_end) { | 780 const base::Time& delete_begin, const base::Time& delete_end) { |
| 820 std::vector<PasswordForm*> forms; | 781 login_metadata_db_->RemoveLoginsCreatedBetween(delete_begin, delete_end); |
| 821 if (login_metadata_db_->GetLoginsCreatedBetween(delete_begin, delete_end, | |
| 822 &forms)) { | |
| 823 if (login_metadata_db_->RemoveLoginsCreatedBetween(delete_begin, | |
| 824 delete_end)) { | |
| 825 // We can't delete from the Keychain by date because we may be sharing | |
| 826 // items with database entries that weren't in the delete range. Instead, | |
| 827 // we find all the Keychain items we own but aren't using any more and | |
| 828 // delete those. | |
| 829 std::vector<PasswordForm*> orphan_keychain_forms = | |
| 830 GetUnusedKeychainForms(); | |
| 831 // This is inefficient, since we have to re-look-up each keychain item | |
| 832 // one at a time to delete it even though the search step already had a | |
| 833 // list of Keychain item references. If this turns out to be noticeably | |
| 834 // slow we'll need to rearchitect to allow the search and deletion steps | |
| 835 // to share. | |
| 836 RemoveKeychainForms(orphan_keychain_forms); | |
| 837 STLDeleteElements(&orphan_keychain_forms); | |
| 838 | 782 |
| 839 PasswordStoreChangeList changes; | 783 // We can't delete from the Keychain by date because we may be sharing items |
| 840 for (std::vector<PasswordForm*>::const_iterator it = forms.begin(); | 784 // with database entries that weren't in the delete range. Instead, we find |
| 841 it != forms.end(); ++it) { | 785 // all the Keychain items we own but aren't using any more and delete those. |
| 842 changes.push_back(PasswordStoreChange(PasswordStoreChange::REMOVE, | 786 std::vector<PasswordForm*> orphan_keychain_forms = GetUnusedKeychainForms(); |
| 843 **it)); | 787 // This is inefficient, since we have to re-look-up each keychain item one at |
| 844 } | 788 // a time to delete it even though the search step already had a list of |
| 845 NotificationService::current()->Notify( | 789 // Keychain item references. If this turns out to be noticeably slow we'll |
| 846 NotificationType::LOGINS_CHANGED, | 790 // need to rearchitect to allow the search and deletion steps to share. |
| 847 NotificationService::AllSources(), | 791 RemoveKeychainForms(orphan_keychain_forms); |
| 848 Details<PasswordStoreChangeList>(&changes)); | 792 STLDeleteElements(&orphan_keychain_forms); |
| 849 } | |
| 850 } | |
| 851 } | 793 } |
| 852 | 794 |
| 853 void PasswordStoreMac::GetLoginsImpl(GetLoginsRequest* request, | 795 void PasswordStoreMac::GetLoginsImpl(GetLoginsRequest* request, |
| 854 const webkit_glue::PasswordForm& form) { | 796 const webkit_glue::PasswordForm& form) { |
| 855 MacKeychainPasswordFormAdapter keychain_adapter(keychain_.get()); | 797 MacKeychainPasswordFormAdapter keychain_adapter(keychain_.get()); |
| 856 std::vector<PasswordForm*> keychain_forms = | 798 std::vector<PasswordForm*> keychain_forms = |
| 857 keychain_adapter.PasswordsFillingForm(form); | 799 keychain_adapter.PasswordsFillingForm(form); |
| 858 | 800 |
| 859 std::vector<PasswordForm*> database_forms; | 801 std::vector<PasswordForm*> database_forms; |
| 860 login_metadata_db_->GetLogins(form, &database_forms); | 802 login_metadata_db_->GetLogins(form, &database_forms); |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 957 | 899 |
| 958 void PasswordStoreMac::RemoveKeychainForms( | 900 void PasswordStoreMac::RemoveKeychainForms( |
| 959 const std::vector<PasswordForm*>& forms) { | 901 const std::vector<PasswordForm*>& forms) { |
| 960 MacKeychainPasswordFormAdapter owned_keychain_adapter(keychain_.get()); | 902 MacKeychainPasswordFormAdapter owned_keychain_adapter(keychain_.get()); |
| 961 owned_keychain_adapter.SetFindsOnlyOwnedItems(true); | 903 owned_keychain_adapter.SetFindsOnlyOwnedItems(true); |
| 962 for (std::vector<PasswordForm*>::const_iterator i = forms.begin(); | 904 for (std::vector<PasswordForm*>::const_iterator i = forms.begin(); |
| 963 i != forms.end(); ++i) { | 905 i != forms.end(); ++i) { |
| 964 owned_keychain_adapter.RemovePassword(**i); | 906 owned_keychain_adapter.RemovePassword(**i); |
| 965 } | 907 } |
| 966 } | 908 } |
| 967 | |
| 968 void PasswordStoreMac::CreateNotificationService() { | |
| 969 notification_service_.reset(new NotificationService); | |
| 970 } | |
| OLD | NEW |