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/stl_util-inl.h" | 14 #include "base/stl_util-inl.h" |
14 #include "base/string_util.h" | 15 #include "base/string_util.h" |
15 #include "chrome/browser/keychain_mac.h" | 16 #include "chrome/browser/keychain_mac.h" |
16 #include "chrome/browser/password_manager/login_database_mac.h" | 17 #include "chrome/browser/password_manager/login_database_mac.h" |
17 | 18 |
18 using webkit_glue::PasswordForm; | 19 using webkit_glue::PasswordForm; |
19 | 20 |
20 static const OSType kChromeKeychainCreatorCode = 'rimZ'; | |
21 | |
22 // Utility class to handle the details of constructing and running a keychain | 21 // Utility class to handle the details of constructing and running a keychain |
23 // search from a set of attributes. | 22 // search from a set of attributes. |
24 class KeychainSearch { | 23 class KeychainSearch { |
25 public: | 24 public: |
26 KeychainSearch(const MacKeychain& keychain); | 25 KeychainSearch(const MacKeychain& keychain); |
27 ~KeychainSearch(); | 26 ~KeychainSearch(); |
28 | 27 |
29 // Sets up a keycahin search based on an non "null" (NULL for char*, | 28 // Sets up a keycahin search based on an non "null" (NULL for char*, |
30 // The appropriate "Any" entry for other types) arguments. | 29 // The appropriate "Any" entry for other types) arguments. |
31 // | 30 // |
(...skipping 399 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
431 database_blacklist_forms.begin(), | 430 database_blacklist_forms.begin(), |
432 database_blacklist_forms.end()); | 431 database_blacklist_forms.end()); |
433 | 432 |
434 // Clear out all the Keychain entries we used. | 433 // Clear out all the Keychain entries we used. |
435 DeleteVectorElementsInSet(keychain_forms, used_keychain_forms); | 434 DeleteVectorElementsInSet(keychain_forms, used_keychain_forms); |
436 } | 435 } |
437 | 436 |
438 std::vector<PasswordForm*> GetPasswordsForForms( | 437 std::vector<PasswordForm*> GetPasswordsForForms( |
439 const MacKeychain& keychain, std::vector<PasswordForm*>* database_forms) { | 438 const MacKeychain& keychain, std::vector<PasswordForm*>* database_forms) { |
440 MacKeychainPasswordFormAdapter keychain_adapter(&keychain); | 439 MacKeychainPasswordFormAdapter keychain_adapter(&keychain); |
441 | 440 |
442 std::vector<PasswordForm*> merged_forms; | 441 std::vector<PasswordForm*> merged_forms; |
443 for (std::vector<PasswordForm*>::iterator i = database_forms->begin(); | 442 for (std::vector<PasswordForm*>::iterator i = database_forms->begin(); |
444 i != database_forms->end();) { | 443 i != database_forms->end();) { |
445 std::vector<PasswordForm*> db_form_container(1, *i); | 444 std::vector<PasswordForm*> db_form_container(1, *i); |
446 std::vector<PasswordForm*> keychain_matches = | 445 std::vector<PasswordForm*> keychain_matches = |
447 keychain_adapter.PasswordsMergeableWithForm(**i); | 446 keychain_adapter.PasswordsMergeableWithForm(**i); |
448 MergePasswordForms(&keychain_matches, &db_form_container, &merged_forms); | 447 MergePasswordForms(&keychain_matches, &db_form_container, &merged_forms); |
449 if (db_form_container.size() == 0) { | 448 if (db_form_container.size() == 0) { |
450 i = database_forms->erase(i); | 449 i = database_forms->erase(i); |
451 } else { | 450 } else { |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
500 return NULL; | 499 return NULL; |
501 } | 500 } |
502 | 501 |
503 std::vector<PasswordForm*> | 502 std::vector<PasswordForm*> |
504 MacKeychainPasswordFormAdapter::GetAllPasswordFormPasswords() { | 503 MacKeychainPasswordFormAdapter::GetAllPasswordFormPasswords() { |
505 SecAuthenticationType supported_auth_types[] = { | 504 SecAuthenticationType supported_auth_types[] = { |
506 kSecAuthenticationTypeHTMLForm, | 505 kSecAuthenticationTypeHTMLForm, |
507 kSecAuthenticationTypeHTTPBasic, | 506 kSecAuthenticationTypeHTTPBasic, |
508 kSecAuthenticationTypeHTTPDigest, | 507 kSecAuthenticationTypeHTTPDigest, |
509 }; | 508 }; |
510 OSType creator = finds_only_owned_ ? kChromeKeychainCreatorCode : 0; | |
511 | 509 |
512 std::vector<SecKeychainItemRef> matches; | 510 std::vector<SecKeychainItemRef> matches; |
513 for (unsigned int i = 0; i < arraysize(supported_auth_types); ++i) { | 511 for (unsigned int i = 0; i < arraysize(supported_auth_types); ++i) { |
514 KeychainSearch keychain_search(*keychain_); | 512 KeychainSearch keychain_search(*keychain_); |
515 keychain_search.Init(NULL, 0, kSecProtocolTypeAny, supported_auth_types[i], | 513 keychain_search.Init(NULL, 0, kSecProtocolTypeAny, supported_auth_types[i], |
516 NULL, NULL, NULL, creator); | 514 NULL, NULL, NULL, CreatorCodeForSearch()); |
517 keychain_search.FindMatchingItems(&matches); | 515 keychain_search.FindMatchingItems(&matches); |
518 } | 516 } |
519 | 517 |
520 return ConvertKeychainItemsToForms(&matches); | 518 return ConvertKeychainItemsToForms(&matches); |
521 } | 519 } |
522 | 520 |
523 bool MacKeychainPasswordFormAdapter::AddPassword(const PasswordForm& form) { | 521 bool MacKeychainPasswordFormAdapter::AddPassword(const PasswordForm& form) { |
524 // We should never be trying to store a blacklist in the keychain. | 522 // We should never be trying to store a blacklist in the keychain. |
525 DCHECK(!form.blacklisted_by_user); | 523 DCHECK(!form.blacklisted_by_user); |
526 | 524 |
(...skipping 13 matching lines...) Expand all Loading... |
540 SecKeychainItemRef new_item = NULL; | 538 SecKeychainItemRef new_item = NULL; |
541 OSStatus result = keychain_->AddInternetPassword( | 539 OSStatus result = keychain_->AddInternetPassword( |
542 NULL, server.size(), server.c_str(), | 540 NULL, server.size(), server.c_str(), |
543 security_domain.size(), security_domain.c_str(), | 541 security_domain.size(), security_domain.c_str(), |
544 username.size(), username.c_str(), | 542 username.size(), username.c_str(), |
545 path.size(), path.c_str(), | 543 path.size(), path.c_str(), |
546 port, protocol, AuthTypeForScheme(form.scheme), | 544 port, protocol, AuthTypeForScheme(form.scheme), |
547 password.size(), password.c_str(), &new_item); | 545 password.size(), password.c_str(), &new_item); |
548 | 546 |
549 if (result == noErr) { | 547 if (result == noErr) { |
550 SetKeychainItemCreatorCode(new_item, kChromeKeychainCreatorCode); | 548 SetKeychainItemCreatorCode(new_item, mac_util::CreatorCodeForApplication()); |
551 keychain_->Free(new_item); | 549 keychain_->Free(new_item); |
552 } else if (result == errSecDuplicateItem) { | 550 } else if (result == errSecDuplicateItem) { |
553 // If we collide with an existing item, find and update it instead. | 551 // If we collide with an existing item, find and update it instead. |
554 SecKeychainItemRef existing_item = KeychainItemForForm(form); | 552 SecKeychainItemRef existing_item = KeychainItemForForm(form); |
555 if (!existing_item) { | 553 if (!existing_item) { |
556 return false; | 554 return false; |
557 } | 555 } |
558 bool changed = SetKeychainItemPassword(existing_item, password); | 556 bool changed = SetKeychainItemPassword(existing_item, password); |
559 keychain_->Free(existing_item); | 557 keychain_->Free(existing_item); |
560 return changed; | 558 return changed; |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
634 // TODO(stuartmorgan): Proxies will currently fail here, since their | 632 // TODO(stuartmorgan): Proxies will currently fail here, since their |
635 // signon_realm is not a URL. We need to detect the proxy case and handle | 633 // signon_realm is not a URL. We need to detect the proxy case and handle |
636 // it specially. | 634 // it specially. |
637 return matches; | 635 return matches; |
638 } | 636 } |
639 SecProtocolType protocol = is_secure ? kSecProtocolTypeHTTPS | 637 SecProtocolType protocol = is_secure ? kSecProtocolTypeHTTPS |
640 : kSecProtocolTypeHTTP; | 638 : kSecProtocolTypeHTTP; |
641 SecAuthenticationType auth_type = AuthTypeForScheme(scheme); | 639 SecAuthenticationType auth_type = AuthTypeForScheme(scheme); |
642 const char* auth_domain = (scheme == PasswordForm::SCHEME_HTML) ? | 640 const char* auth_domain = (scheme == PasswordForm::SCHEME_HTML) ? |
643 NULL : security_domain.c_str(); | 641 NULL : security_domain.c_str(); |
644 OSType creator = finds_only_owned_ ? kChromeKeychainCreatorCode : 0; | |
645 | |
646 KeychainSearch keychain_search(*keychain_); | 642 KeychainSearch keychain_search(*keychain_); |
647 keychain_search.Init(server.c_str(), port, protocol, auth_type, | 643 keychain_search.Init(server.c_str(), port, protocol, auth_type, |
648 auth_domain, path, username, creator); | 644 auth_domain, path, username, CreatorCodeForSearch()); |
649 keychain_search.FindMatchingItems(&matches); | 645 keychain_search.FindMatchingItems(&matches); |
650 return matches; | 646 return matches; |
651 } | 647 } |
652 | 648 |
653 // TODO(stuartmorgan): signon_realm for proxies is not yet supported. | 649 // TODO(stuartmorgan): signon_realm for proxies is not yet supported. |
654 bool MacKeychainPasswordFormAdapter::ExtractSignonRealmComponents( | 650 bool MacKeychainPasswordFormAdapter::ExtractSignonRealmComponents( |
655 const std::string& signon_realm, std::string* server, int* port, | 651 const std::string& signon_realm, std::string* server, int* port, |
656 bool* is_secure, std::string* security_domain) { | 652 bool* is_secure, std::string* security_domain) { |
657 // The signon_realm will be the Origin portion of a URL for an HTML form, | 653 // The signon_realm will be the Origin portion of a URL for an HTML form, |
658 // and the same but with the security domain as a path for HTTP auth. | 654 // and the same but with the security domain as a path for HTTP auth. |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
698 bool MacKeychainPasswordFormAdapter::SetKeychainItemCreatorCode( | 694 bool MacKeychainPasswordFormAdapter::SetKeychainItemCreatorCode( |
699 const SecKeychainItemRef& keychain_item, OSType creator_code) { | 695 const SecKeychainItemRef& keychain_item, OSType creator_code) { |
700 SecKeychainAttribute attr = { kSecCreatorItemAttr, sizeof(creator_code), | 696 SecKeychainAttribute attr = { kSecCreatorItemAttr, sizeof(creator_code), |
701 &creator_code }; | 697 &creator_code }; |
702 SecKeychainAttributeList attrList = { 1, &attr }; | 698 SecKeychainAttributeList attrList = { 1, &attr }; |
703 OSStatus result = keychain_->ItemModifyAttributesAndData(keychain_item, | 699 OSStatus result = keychain_->ItemModifyAttributesAndData(keychain_item, |
704 &attrList, 0, NULL); | 700 &attrList, 0, NULL); |
705 return result == noErr; | 701 return result == noErr; |
706 } | 702 } |
707 | 703 |
| 704 OSType MacKeychainPasswordFormAdapter::CreatorCodeForSearch() { |
| 705 return finds_only_owned_ ? mac_util::CreatorCodeForApplication() : 0; |
| 706 } |
| 707 |
708 #pragma mark - | 708 #pragma mark - |
709 | 709 |
710 PasswordStoreMac::PasswordStoreMac(MacKeychain* keychain, | 710 PasswordStoreMac::PasswordStoreMac(MacKeychain* keychain, |
711 LoginDatabaseMac* login_db) | 711 LoginDatabaseMac* login_db) |
712 : keychain_(keychain), login_metadata_db_(login_db) { | 712 : keychain_(keychain), login_metadata_db_(login_db) { |
713 DCHECK(keychain_.get()); | 713 DCHECK(keychain_.get()); |
714 DCHECK(login_metadata_db_.get()); | 714 DCHECK(login_metadata_db_.get()); |
715 } | 715 } |
716 | 716 |
717 PasswordStoreMac::~PasswordStoreMac() {} | 717 PasswordStoreMac::~PasswordStoreMac() {} |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
806 | 806 |
807 void PasswordStoreMac::GetBlacklistLoginsImpl(GetLoginsRequest* request) { | 807 void PasswordStoreMac::GetBlacklistLoginsImpl(GetLoginsRequest* request) { |
808 std::vector<PasswordForm*> database_forms; | 808 std::vector<PasswordForm*> database_forms; |
809 login_metadata_db_->GetBlacklistLogins(&database_forms); | 809 login_metadata_db_->GetBlacklistLogins(&database_forms); |
810 NotifyConsumer(request, database_forms); | 810 NotifyConsumer(request, database_forms); |
811 } | 811 } |
812 | 812 |
813 void PasswordStoreMac::GetAutofillableLoginsImpl(GetLoginsRequest* request) { | 813 void PasswordStoreMac::GetAutofillableLoginsImpl(GetLoginsRequest* request) { |
814 std::vector<PasswordForm*> database_forms; | 814 std::vector<PasswordForm*> database_forms; |
815 login_metadata_db_->GetAutofillableLogins(&database_forms); | 815 login_metadata_db_->GetAutofillableLogins(&database_forms); |
816 | 816 |
817 std::vector<PasswordForm*> merged_forms = | 817 std::vector<PasswordForm*> merged_forms = |
818 internal_keychain_helpers::GetPasswordsForForms(*keychain_, | 818 internal_keychain_helpers::GetPasswordsForForms(*keychain_, |
819 &database_forms); | 819 &database_forms); |
820 | 820 |
821 // Clean up any orphaned database entries. | 821 // Clean up any orphaned database entries. |
822 RemoveDatabaseForms(database_forms); | 822 RemoveDatabaseForms(database_forms); |
823 STLDeleteElements(&database_forms); | 823 STLDeleteElements(&database_forms); |
824 | 824 |
825 NotifyConsumer(request, merged_forms); | 825 NotifyConsumer(request, merged_forms); |
826 } | 826 } |
827 | 827 |
828 bool PasswordStoreMac::AddToKeychainIfNecessary(const PasswordForm& form) { | 828 bool PasswordStoreMac::AddToKeychainIfNecessary(const PasswordForm& form) { |
829 if (form.blacklisted_by_user) { | 829 if (form.blacklisted_by_user) { |
830 return true; | 830 return true; |
831 } | 831 } |
832 MacKeychainPasswordFormAdapter keychainAdapter(keychain_.get()); | 832 MacKeychainPasswordFormAdapter keychainAdapter(keychain_.get()); |
833 return keychainAdapter.AddPassword(form); | 833 return keychainAdapter.AddPassword(form); |
834 } | 834 } |
(...skipping 11 matching lines...) Expand all Loading... |
846 break; | 846 break; |
847 } | 847 } |
848 } | 848 } |
849 STLDeleteElements(&database_forms); | 849 STLDeleteElements(&database_forms); |
850 return has_match; | 850 return has_match; |
851 } | 851 } |
852 | 852 |
853 std::vector<PasswordForm*> PasswordStoreMac::GetUnusedKeychainForms() { | 853 std::vector<PasswordForm*> PasswordStoreMac::GetUnusedKeychainForms() { |
854 std::vector<PasswordForm*> database_forms; | 854 std::vector<PasswordForm*> database_forms; |
855 login_metadata_db_->GetAutofillableLogins(&database_forms); | 855 login_metadata_db_->GetAutofillableLogins(&database_forms); |
856 | 856 |
857 MacKeychainPasswordFormAdapter owned_keychain_adapter(keychain_.get()); | 857 MacKeychainPasswordFormAdapter owned_keychain_adapter(keychain_.get()); |
858 owned_keychain_adapter.SetFindsOnlyOwnedItems(true); | 858 owned_keychain_adapter.SetFindsOnlyOwnedItems(true); |
859 std::vector<PasswordForm*> owned_keychain_forms = | 859 std::vector<PasswordForm*> owned_keychain_forms = |
860 owned_keychain_adapter.GetAllPasswordFormPasswords(); | 860 owned_keychain_adapter.GetAllPasswordFormPasswords(); |
861 | 861 |
862 // Run a merge; anything left in owned_keychain_forms when we are done no | 862 // Run a merge; anything left in owned_keychain_forms when we are done no |
863 // longer has a matching database entry. | 863 // longer has a matching database entry. |
864 std::vector<PasswordForm*> merged_forms; | 864 std::vector<PasswordForm*> merged_forms; |
865 internal_keychain_helpers::MergePasswordForms(&owned_keychain_forms, | 865 internal_keychain_helpers::MergePasswordForms(&owned_keychain_forms, |
866 &database_forms, | 866 &database_forms, |
867 &merged_forms); | 867 &merged_forms); |
868 STLDeleteElements(&merged_forms); | 868 STLDeleteElements(&merged_forms); |
869 STLDeleteElements(&database_forms); | 869 STLDeleteElements(&database_forms); |
870 | 870 |
871 return owned_keychain_forms; | 871 return owned_keychain_forms; |
872 } | 872 } |
873 | 873 |
874 void PasswordStoreMac::RemoveDatabaseForms( | 874 void PasswordStoreMac::RemoveDatabaseForms( |
875 const std::vector<PasswordForm*>& forms) { | 875 const std::vector<PasswordForm*>& forms) { |
876 for (std::vector<PasswordForm*>::const_iterator i = forms.begin(); | 876 for (std::vector<PasswordForm*>::const_iterator i = forms.begin(); |
877 i != forms.end(); ++i) { | 877 i != forms.end(); ++i) { |
878 login_metadata_db_->RemoveLogin(**i); | 878 login_metadata_db_->RemoveLogin(**i); |
879 } | 879 } |
880 } | 880 } |
881 | 881 |
882 void PasswordStoreMac::RemoveKeychainForms( | 882 void PasswordStoreMac::RemoveKeychainForms( |
883 const std::vector<PasswordForm*>& forms) { | 883 const std::vector<PasswordForm*>& forms) { |
884 MacKeychainPasswordFormAdapter owned_keychain_adapter(keychain_.get()); | 884 MacKeychainPasswordFormAdapter owned_keychain_adapter(keychain_.get()); |
885 owned_keychain_adapter.SetFindsOnlyOwnedItems(true); | 885 owned_keychain_adapter.SetFindsOnlyOwnedItems(true); |
886 for (std::vector<PasswordForm*>::const_iterator i = forms.begin(); | 886 for (std::vector<PasswordForm*>::const_iterator i = forms.begin(); |
887 i != forms.end(); ++i) { | 887 i != forms.end(); ++i) { |
888 owned_keychain_adapter.RemovePassword(**i); | 888 owned_keychain_adapter.RemovePassword(**i); |
889 } | 889 } |
890 } | 890 } |
OLD | NEW |