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