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

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

Issue 155451: Support individual Keychain item deletion (Closed)
Patch Set: Created 11 years, 5 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) 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>
(...skipping 16 matching lines...) Expand all
27 ~KeychainSearch(); 27 ~KeychainSearch();
28 28
29 // Sets up a keycahin search based on an non "null" (NULL for char*, 29 // Sets up a keycahin search based on an non "null" (NULL for char*,
30 // The appropriate "Any" entry for other types) arguments. 30 // The appropriate "Any" entry for other types) arguments.
31 // 31 //
32 // IMPORTANT: Any paramaters passed in *must* remain valid for as long as the 32 // IMPORTANT: Any paramaters passed in *must* remain valid for as long as the
33 // KeychainSearch object, since the search uses them by reference. 33 // KeychainSearch object, since the search uses them by reference.
34 void Init(const char* server, const UInt32& port, 34 void Init(const char* server, const UInt32& port,
35 const SecProtocolType& protocol, 35 const SecProtocolType& protocol,
36 const SecAuthenticationType& auth_type, const char* security_domain, 36 const SecAuthenticationType& auth_type, const char* security_domain,
37 const char* path, const char* username); 37 const char* path, const char* username, OSType creator);
38 38
39 // Fills |items| with all Keychain items that match the Init'd search. 39 // Fills |items| with all Keychain items that match the Init'd search.
40 // If the search fails for any reason, |items| will be unchanged. 40 // If the search fails for any reason, |items| will be unchanged.
41 void FindMatchingItems(std::vector<SecKeychainItemRef>* matches); 41 void FindMatchingItems(std::vector<SecKeychainItemRef>* matches);
42 42
43 private: 43 private:
44 const MacKeychain* keychain_; 44 const MacKeychain* keychain_;
45 SecKeychainAttributeList search_attributes_; 45 SecKeychainAttributeList search_attributes_;
46 SecKeychainSearchRef search_ref_; 46 SecKeychainSearchRef search_ref_;
47 }; 47 };
48 48
49 KeychainSearch::KeychainSearch(const MacKeychain& keychain) 49 KeychainSearch::KeychainSearch(const MacKeychain& keychain)
50 : keychain_(&keychain), search_ref_(NULL) { 50 : keychain_(&keychain), search_ref_(NULL) {
51 search_attributes_.count = 0; 51 search_attributes_.count = 0;
52 search_attributes_.attr = NULL; 52 search_attributes_.attr = NULL;
53 } 53 }
54 54
55 KeychainSearch::~KeychainSearch() { 55 KeychainSearch::~KeychainSearch() {
56 if (search_attributes_.attr) { 56 if (search_attributes_.attr) {
57 free(search_attributes_.attr); 57 free(search_attributes_.attr);
58 } 58 }
59 } 59 }
60 60
61 void KeychainSearch::Init(const char* server, const UInt32& port, 61 void KeychainSearch::Init(const char* server, const UInt32& port,
62 const SecProtocolType& protocol, 62 const SecProtocolType& protocol,
63 const SecAuthenticationType& auth_type, 63 const SecAuthenticationType& auth_type,
64 const char* security_domain, const char* path, 64 const char* security_domain, const char* path,
65 const char* username) { 65 const char* username, OSType creator) {
66 // Allocate enough to hold everything we might use. 66 // Allocate enough to hold everything we might use.
67 const unsigned int kMaxEntryCount = 7; 67 const unsigned int kMaxEntryCount = 8;
68 search_attributes_.attr = 68 search_attributes_.attr =
69 static_cast<SecKeychainAttribute*>(calloc(kMaxEntryCount, 69 static_cast<SecKeychainAttribute*>(calloc(kMaxEntryCount,
70 sizeof(SecKeychainAttribute))); 70 sizeof(SecKeychainAttribute)));
71 unsigned int entries = 0; 71 unsigned int entries = 0;
72 // We only use search_attributes_ with SearchCreateFromAttributes, which takes 72 // We only use search_attributes_ with SearchCreateFromAttributes, which takes
73 // a "const SecKeychainAttributeList *", so we trust that they won't try 73 // a "const SecKeychainAttributeList *", so we trust that they won't try
74 // to modify the list, and that casting away const-ness is thus safe. 74 // to modify the list, and that casting away const-ness is thus safe.
75 if (server != NULL) { 75 if (server != NULL) {
76 DCHECK(entries < kMaxEntryCount); 76 DCHECK(entries < kMaxEntryCount);
77 search_attributes_.attr[entries].tag = kSecServerItemAttr; 77 search_attributes_.attr[entries].tag = kSecServerItemAttr;
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
121 ++entries; 121 ++entries;
122 } 122 }
123 if (username != NULL) { 123 if (username != NULL) {
124 DCHECK(entries <= kMaxEntryCount); 124 DCHECK(entries <= kMaxEntryCount);
125 search_attributes_.attr[entries].tag = kSecAccountItemAttr; 125 search_attributes_.attr[entries].tag = kSecAccountItemAttr;
126 search_attributes_.attr[entries].length = strlen(username); 126 search_attributes_.attr[entries].length = strlen(username);
127 search_attributes_.attr[entries].data = 127 search_attributes_.attr[entries].data =
128 const_cast<void*>(reinterpret_cast<const void*>(username)); 128 const_cast<void*>(reinterpret_cast<const void*>(username));
129 ++entries; 129 ++entries;
130 } 130 }
131 if (creator != 0) {
132 DCHECK(entries <= kMaxEntryCount);
133 search_attributes_.attr[entries].tag = kSecCreatorItemAttr;
134 search_attributes_.attr[entries].length = sizeof(creator);
135 search_attributes_.attr[entries].data =
136 const_cast<void*>(reinterpret_cast<const void*>(&creator));
137 ++entries;
138 }
131 search_attributes_.count = entries; 139 search_attributes_.count = entries;
132 } 140 }
133 141
134 void KeychainSearch::FindMatchingItems(std::vector<SecKeychainItemRef>* items) { 142 void KeychainSearch::FindMatchingItems(std::vector<SecKeychainItemRef>* items) {
135 OSStatus result = keychain_->SearchCreateFromAttributes( 143 OSStatus result = keychain_->SearchCreateFromAttributes(
136 NULL, kSecInternetPasswordItemClass, &search_attributes_, &search_ref_); 144 NULL, kSecInternetPasswordItemClass, &search_attributes_, &search_ref_);
137 145
138 if (result != noErr) { 146 if (result != noErr) {
139 LOG(ERROR) << "Keychain lookup failed with error " << result; 147 LOG(ERROR) << "Keychain lookup failed with error " << result;
140 return; 148 return;
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after
321 form->origin = URLFromComponents(form->ssl_valid, server, port, path); 329 form->origin = URLFromComponents(form->ssl_valid, server, port, path);
322 // TODO(stuartmorgan): Handle proxies, which need a different signon_realm 330 // TODO(stuartmorgan): Handle proxies, which need a different signon_realm
323 // format. 331 // format.
324 form->signon_realm = form->origin.GetOrigin().spec(); 332 form->signon_realm = form->origin.GetOrigin().spec();
325 if (form->scheme != PasswordForm::SCHEME_HTML) { 333 if (form->scheme != PasswordForm::SCHEME_HTML) {
326 form->signon_realm.append(security_domain); 334 form->signon_realm.append(security_domain);
327 } 335 }
328 return true; 336 return true;
329 } 337 }
330 338
331 bool FormsMatchForMerge(const PasswordForm& form_a, const PasswordForm& form_b, 339 bool FormsMatchForMerge(const PasswordForm& form_a,
332 bool* path_matches) { 340 const PasswordForm& form_b) {
333 // We never merge blacklist entries between our store and the keychain. 341 // We never merge blacklist entries between our store and the keychain.
334 if (form_a.blacklisted_by_user || form_b.blacklisted_by_user) { 342 if (form_a.blacklisted_by_user || form_b.blacklisted_by_user) {
335 return false; 343 return false;
336 } 344 }
337 bool matches = form_a.scheme == form_b.scheme && 345 return form_a.scheme == form_b.scheme &&
338 form_a.signon_realm == form_b.signon_realm && 346 form_a.signon_realm == form_b.signon_realm &&
339 form_a.username_value == form_b.username_value; 347 form_a.username_value == form_b.username_value;
340 if (matches && path_matches) {
341 *path_matches = (form_a.origin == form_b.origin);
342 }
343 return matches;
344 } 348 }
345 349
346 // Returns an the best match for |form| from |keychain_forms|, or NULL if there 350 // Returns an the best match for |form| from |keychain_forms|, or NULL if there
347 // is no suitable match. 351 // is no suitable match.
348 PasswordForm* BestKeychainFormForForm( 352 PasswordForm* BestKeychainFormForForm(
349 const PasswordForm& base_form, 353 const PasswordForm& base_form,
350 const std::vector<PasswordForm*>* keychain_forms) { 354 const std::vector<PasswordForm*>* keychain_forms) {
351 PasswordForm* partial_match = NULL; 355 PasswordForm* partial_match = NULL;
352 for (std::vector<PasswordForm*>::const_iterator i = keychain_forms->begin(); 356 for (std::vector<PasswordForm*>::const_iterator i = keychain_forms->begin();
353 i != keychain_forms->end(); ++i) { 357 i != keychain_forms->end(); ++i) {
354 // TODO(stuartmorgan): We should really be scoring path matches and picking 358 // TODO(stuartmorgan): We should really be scoring path matches and picking
355 // the best, rather than just checking exact-or-not (although in practice 359 // the best, rather than just checking exact-or-not (although in practice
356 // keychain items with paths probably came from us). 360 // keychain items with paths probably came from us).
357 bool path_matches = false; 361 if (FormsMatchForMerge(base_form, *(*i))) {
358 if (FormsMatchForMerge(base_form, *(*i), &path_matches)) { 362 if (base_form.origin == (*i)->origin) {
359 if (path_matches) {
360 return *i; 363 return *i;
361 } else if (!partial_match) { 364 } else if (!partial_match) {
362 partial_match = *i; 365 partial_match = *i;
363 } 366 }
364 } 367 }
365 } 368 }
366 return partial_match; 369 return partial_match;
367 } 370 }
368 371
369 void MergePasswordForms(std::vector<PasswordForm*>* keychain_forms, 372 void MergePasswordForms(std::vector<PasswordForm*>* keychain_forms,
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
409 i = keychain_forms->erase(i); 412 i = keychain_forms->erase(i);
410 } 413 }
411 } 414 }
412 } 415 }
413 416
414 } // namespace internal_keychain_helpers 417 } // namespace internal_keychain_helpers
415 418
416 #pragma mark - 419 #pragma mark -
417 420
418 MacKeychainPasswordFormAdapter::MacKeychainPasswordFormAdapter( 421 MacKeychainPasswordFormAdapter::MacKeychainPasswordFormAdapter(
419 MacKeychain* keychain) : keychain_(keychain) { 422 MacKeychain* keychain) : keychain_(keychain), finds_only_owned_(false) {
420 } 423 }
421 424
422 std::vector<PasswordForm*> 425 std::vector<PasswordForm*>
423 MacKeychainPasswordFormAdapter::PasswordsMatchingForm( 426 MacKeychainPasswordFormAdapter::PasswordsMatchingForm(
424 const PasswordForm& query_form) { 427 const PasswordForm& query_form) {
425 std::vector<SecKeychainItemRef> keychain_items = 428 std::vector<SecKeychainItemRef> keychain_items =
426 KeychainItemsForFillingForm(query_form); 429 KeychainItemsForFillingForm(query_form);
427 430
428 std::vector<PasswordForm*> keychain_forms = 431 std::vector<PasswordForm*> keychain_forms =
429 CreateFormsFromKeychainItems(keychain_items); 432 CreateFormsFromKeychainItems(keychain_items);
(...skipping 11 matching lines...) Expand all
441 PasswordForm* form = new PasswordForm(); 444 PasswordForm* form = new PasswordForm();
442 internal_keychain_helpers::FillPasswordFormFromKeychainItem(*keychain_, 445 internal_keychain_helpers::FillPasswordFormFromKeychainItem(*keychain_,
443 keychain_item, 446 keychain_item,
444 form); 447 form);
445 keychain_->Free(keychain_item); 448 keychain_->Free(keychain_item);
446 return form; 449 return form;
447 } 450 }
448 return NULL; 451 return NULL;
449 } 452 }
450 453
451 bool MacKeychainPasswordFormAdapter::AddLogin(const PasswordForm& form) { 454 bool MacKeychainPasswordFormAdapter::AddPassword(const PasswordForm& form) {
452 // We should never be trying to store a blacklist in the keychain. 455 // We should never be trying to store a blacklist in the keychain.
453 DCHECK(!form.blacklisted_by_user); 456 DCHECK(!form.blacklisted_by_user);
454 457
455 std::string server; 458 std::string server;
456 std::string security_domain; 459 std::string security_domain;
457 int port; 460 int port;
458 bool is_secure; 461 bool is_secure;
459 if (!ExtractSignonRealmComponents(form.signon_realm, &server, &port, 462 if (!ExtractSignonRealmComponents(form.signon_realm, &server, &port,
460 &is_secure, &security_domain)) { 463 &is_secure, &security_domain)) {
461 return false; 464 return false;
(...skipping 22 matching lines...) Expand all
484 return false; 487 return false;
485 } 488 }
486 bool changed = SetKeychainItemPassword(existing_item, password); 489 bool changed = SetKeychainItemPassword(existing_item, password);
487 keychain_->Free(existing_item); 490 keychain_->Free(existing_item);
488 return changed; 491 return changed;
489 } 492 }
490 493
491 return result == noErr; 494 return result == noErr;
492 } 495 }
493 496
497 bool MacKeychainPasswordFormAdapter::RemovePassword(const PasswordForm& form) {
498 SecKeychainItemRef keychain_item = KeychainItemForForm(form);
499 if (keychain_item == NULL)
500 return false;
501 OSStatus result = keychain_->ItemDelete(keychain_item);
502 keychain_->Free(keychain_item);
503 return result == noErr;
504 }
505
506 void MacKeychainPasswordFormAdapter::SetFindsOnlyOwnedItems(
507 bool finds_only_owned) {
508 finds_only_owned_ = finds_only_owned;
509 }
510
494 std::vector<PasswordForm*> 511 std::vector<PasswordForm*>
495 MacKeychainPasswordFormAdapter::CreateFormsFromKeychainItems( 512 MacKeychainPasswordFormAdapter::CreateFormsFromKeychainItems(
496 const std::vector<SecKeychainItemRef>& items) { 513 const std::vector<SecKeychainItemRef>& items) {
497 std::vector<PasswordForm*> keychain_forms; 514 std::vector<PasswordForm*> keychain_forms;
498 for (std::vector<SecKeychainItemRef>::const_iterator i = items.begin(); 515 for (std::vector<SecKeychainItemRef>::const_iterator i = items.begin();
499 i != items.end(); ++i) { 516 i != items.end(); ++i) {
500 PasswordForm* form = new PasswordForm(); 517 PasswordForm* form = new PasswordForm();
501 if (internal_keychain_helpers::FillPasswordFormFromKeychainItem(*keychain_, 518 if (internal_keychain_helpers::FillPasswordFormFromKeychainItem(*keychain_,
502 *i, form)) { 519 *i, form)) {
503 keychain_forms.push_back(form); 520 keychain_forms.push_back(form);
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
552 // TODO(stuartmorgan): Proxies will currently fail here, since their 569 // TODO(stuartmorgan): Proxies will currently fail here, since their
553 // signon_realm is not a URL. We need to detect the proxy case and handle 570 // signon_realm is not a URL. We need to detect the proxy case and handle
554 // it specially. 571 // it specially.
555 return matches; 572 return matches;
556 } 573 }
557 SecProtocolType protocol = is_secure ? kSecProtocolTypeHTTPS 574 SecProtocolType protocol = is_secure ? kSecProtocolTypeHTTPS
558 : kSecProtocolTypeHTTP; 575 : kSecProtocolTypeHTTP;
559 SecAuthenticationType auth_type = AuthTypeForScheme(scheme); 576 SecAuthenticationType auth_type = AuthTypeForScheme(scheme);
560 const char* auth_domain = (scheme == PasswordForm::SCHEME_HTML) ? 577 const char* auth_domain = (scheme == PasswordForm::SCHEME_HTML) ?
561 NULL : security_domain.c_str(); 578 NULL : security_domain.c_str();
579 OSType creator = finds_only_owned_ ? kChromeKeychainCreatorCode : 0;
562 580
563 KeychainSearch keychain_search(*keychain_); 581 KeychainSearch keychain_search(*keychain_);
564 keychain_search.Init(server.c_str(), port, protocol, auth_type, 582 keychain_search.Init(server.c_str(), port, protocol, auth_type,
565 auth_domain, path, username); 583 auth_domain, path, username, creator);
566 keychain_search.FindMatchingItems(&matches); 584 keychain_search.FindMatchingItems(&matches);
567 return matches; 585 return matches;
568 } 586 }
569 587
570 // TODO(stuartmorgan): signon_realm for proxies is not yet supported. 588 // TODO(stuartmorgan): signon_realm for proxies is not yet supported.
571 bool MacKeychainPasswordFormAdapter::ExtractSignonRealmComponents( 589 bool MacKeychainPasswordFormAdapter::ExtractSignonRealmComponents(
572 const std::string& signon_realm, std::string* server, int* port, 590 const std::string& signon_realm, std::string* server, int* port,
573 bool* is_secure, std::string* security_domain) { 591 bool* is_secure, std::string* security_domain) {
574 // The signon_realm will be the Origin portion of a URL for an HTML form, 592 // The signon_realm will be the Origin portion of a URL for an HTML form,
575 // and the same but with the security domain as a path for HTTP auth. 593 // and the same but with the security domain as a path for HTTP auth.
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
633 651
634 PasswordStoreMac::~PasswordStoreMac() {} 652 PasswordStoreMac::~PasswordStoreMac() {}
635 653
636 void PasswordStoreMac::AddLoginImpl(const PasswordForm& form) { 654 void PasswordStoreMac::AddLoginImpl(const PasswordForm& form) {
637 if (AddToKeychainIfNecessary(form)) { 655 if (AddToKeychainIfNecessary(form)) {
638 login_metadata_db_->AddLogin(form); 656 login_metadata_db_->AddLogin(form);
639 } 657 }
640 } 658 }
641 659
642 void PasswordStoreMac::UpdateLoginImpl(const PasswordForm& form) { 660 void PasswordStoreMac::UpdateLoginImpl(const PasswordForm& form) {
643 // The keychain AddLogin will update if there is a collision and add if there 661 // The keychain add will update if there is a collision and add if there
644 // isn't, which is the behavior we want, so there's no separate UpdateLogin. 662 // isn't, which is the behavior we want, so there's no separate update call.
645 if (AddToKeychainIfNecessary(form)) { 663 if (AddToKeychainIfNecessary(form)) {
646 int update_count = 0; 664 int update_count = 0;
647 login_metadata_db_->UpdateLogin(form, &update_count); 665 login_metadata_db_->UpdateLogin(form, &update_count);
648 // Update will catch any database entries that we already had, but we could 666 // Update will catch any database entries that we already had, but we could
649 // also be updating a keychain-only form, in which case we need to add. 667 // also be updating a keychain-only form, in which case we need to add.
650 if (update_count == 0) { 668 if (update_count == 0) {
651 login_metadata_db_->AddLogin(form); 669 login_metadata_db_->AddLogin(form);
652 } 670 }
653 } 671 }
654 } 672 }
655 673
656 void PasswordStoreMac::RemoveLoginImpl(const PasswordForm& form) { 674 void PasswordStoreMac::RemoveLoginImpl(const PasswordForm& form) {
657 NOTIMPLEMENTED(); 675 login_metadata_db_->RemoveLogin(form);
676
677 // See if we own a Keychain item associated with this item. We can do an exact
678 // search rather than messing around with trying to do fuzzy matching because
679 // passwords that we created will always have an exact-match database entry.
680 // (If a user does lose their profile but not their keychain we'll treat the
681 // entries we find like other imported entries anyway, so it's reasonable to
682 // handle deletes on them the way we would for an imported item.)
683 MacKeychainPasswordFormAdapter owned_keychain_adapter(keychain_.get());
684 owned_keychain_adapter.SetFindsOnlyOwnedItems(true);
685 PasswordForm* owned_password_form =
686 owned_keychain_adapter.PasswordExactlyMatchingForm(form);
687 if (owned_password_form) {
688 // If we don't have other forms using it (i.e., a form differing only by
689 // the names of the form elements), delete the keychain entry.
690 if (!DatabaseHasFormMatchingKeychainForm(form)) {
691 owned_keychain_adapter.RemovePassword(form);
692 }
693 }
658 } 694 }
659 695
660 void PasswordStoreMac::RemoveLoginsCreatedBetweenImpl( 696 void PasswordStoreMac::RemoveLoginsCreatedBetweenImpl(
661 const base::Time& delete_begin, const base::Time& delete_end) { 697 const base::Time& delete_begin, const base::Time& delete_end) {
662 NOTIMPLEMENTED(); 698 NOTIMPLEMENTED();
663 } 699 }
664 700
665 void PasswordStoreMac::GetLoginsImpl(GetLoginsRequest* request, 701 void PasswordStoreMac::GetLoginsImpl(GetLoginsRequest* request,
666 const webkit_glue::PasswordForm& form) { 702 const webkit_glue::PasswordForm& form) {
667 MacKeychainPasswordFormAdapter keychainAdapter(keychain_.get()); 703 MacKeychainPasswordFormAdapter keychain_adapter(keychain_.get());
668 std::vector<PasswordForm*> keychain_forms = 704 std::vector<PasswordForm*> keychain_forms =
669 keychainAdapter.PasswordsMatchingForm(form); 705 keychain_adapter.PasswordsMatchingForm(form);
670 706
671 std::vector<PasswordForm*> database_forms; 707 std::vector<PasswordForm*> database_forms;
672 login_metadata_db_->GetLogins(form, &database_forms); 708 login_metadata_db_->GetLogins(form, &database_forms);
673 709
674 std::vector<PasswordForm*> merged_forms; 710 std::vector<PasswordForm*> merged_forms;
675 internal_keychain_helpers::MergePasswordForms(&keychain_forms, 711 internal_keychain_helpers::MergePasswordForms(&keychain_forms,
676 &database_forms, 712 &database_forms,
677 &merged_forms); 713 &merged_forms);
678 714
679 // Clean up any orphaned database entries. 715 // Clean up any orphaned database entries.
(...skipping 14 matching lines...) Expand all
694 730
695 void PasswordStoreMac::GetAllAutofillableLoginsImpl(GetLoginsRequest* request) { 731 void PasswordStoreMac::GetAllAutofillableLoginsImpl(GetLoginsRequest* request) {
696 NOTIMPLEMENTED(); 732 NOTIMPLEMENTED();
697 } 733 }
698 734
699 bool PasswordStoreMac::AddToKeychainIfNecessary(const PasswordForm& form) { 735 bool PasswordStoreMac::AddToKeychainIfNecessary(const PasswordForm& form) {
700 if (form.blacklisted_by_user) { 736 if (form.blacklisted_by_user) {
701 return true; 737 return true;
702 } 738 }
703 MacKeychainPasswordFormAdapter keychainAdapter(keychain_.get()); 739 MacKeychainPasswordFormAdapter keychainAdapter(keychain_.get());
704 return keychainAdapter.AddLogin(form); 740 return keychainAdapter.AddPassword(form);
705 } 741 }
742
743 bool PasswordStoreMac::DatabaseHasFormMatchingKeychainForm(
744 const webkit_glue::PasswordForm& form) {
745 bool has_match = false;
746 std::vector<PasswordForm*> database_forms;
747 login_metadata_db_->GetLogins(form, &database_forms);
748 for (std::vector<PasswordForm*>::iterator i = database_forms.begin();
749 i != database_forms.end(); ++i) {
750 if (internal_keychain_helpers::FormsMatchForMerge(form, **i) &&
751 (*i)->origin == form.origin) {
752 has_match = true;
753 break;
754 }
755 }
756 STLDeleteElements(&database_forms);
757 return has_match;
758 }
OLDNEW
« no previous file with comments | « chrome/browser/password_manager/password_store_mac.h ('k') | chrome/browser/password_manager/password_store_mac_internal.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698