Home | History | Annotate | Download | only in password_manager
      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
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/password_manager/password_store_mac.h"
      6 #include "chrome/browser/password_manager/password_store_mac_internal.h"
      7 
      8 #include <CoreServices/CoreServices.h>
      9 #include <set>
     10 #include <string>
     11 #include <utility>
     12 #include <vector>
     13 
     14 #include "base/callback.h"
     15 #include "base/logging.h"
     16 #include "base/mac/mac_logging.h"
     17 #include "base/mac/mac_util.h"
     18 #include "base/message_loop/message_loop.h"
     19 #include "base/stl_util.h"
     20 #include "base/strings/string_util.h"
     21 #include "base/strings/utf_string_conversions.h"
     22 #include "chrome/browser/mac/security_wrappers.h"
     23 #include "components/password_manager/core/browser/login_database.h"
     24 #include "components/password_manager/core/browser/password_store_change.h"
     25 #include "content/public/browser/browser_thread.h"
     26 #include "crypto/apple_keychain.h"
     27 
     28 using autofill::PasswordForm;
     29 using crypto::AppleKeychain;
     30 using password_manager::PasswordStoreChange;
     31 using password_manager::PasswordStoreChangeList;
     32 
     33 // Utility class to handle the details of constructing and running a keychain
     34 // search from a set of attributes.
     35 class KeychainSearch {
     36  public:
     37   explicit KeychainSearch(const AppleKeychain& keychain);
     38   ~KeychainSearch();
     39 
     40   // Sets up a keycahin search based on an non "null" (NULL for char*,
     41   // The appropriate "Any" entry for other types) arguments.
     42   //
     43   // IMPORTANT: Any paramaters passed in *must* remain valid for as long as the
     44   // KeychainSearch object, since the search uses them by reference.
     45   void Init(const char* server, const UInt32& port,
     46             const SecProtocolType& protocol,
     47             const SecAuthenticationType& auth_type, const char* security_domain,
     48             const char* path, const char* username, OSType creator);
     49 
     50   // Fills |items| with all Keychain items that match the Init'd search.
     51   // If the search fails for any reason, |items| will be unchanged.
     52   void FindMatchingItems(std::vector<SecKeychainItemRef>* matches);
     53 
     54  private:
     55   const AppleKeychain* keychain_;
     56   SecKeychainAttributeList search_attributes_;
     57   SecKeychainSearchRef search_ref_;
     58 };
     59 
     60 KeychainSearch::KeychainSearch(const AppleKeychain& keychain)
     61     : keychain_(&keychain), search_ref_(NULL) {
     62   search_attributes_.count = 0;
     63   search_attributes_.attr = NULL;
     64 }
     65 
     66 KeychainSearch::~KeychainSearch() {
     67   if (search_attributes_.attr) {
     68     free(search_attributes_.attr);
     69   }
     70 }
     71 
     72 void KeychainSearch::Init(const char* server, const UInt32& port,
     73                           const SecProtocolType& protocol,
     74                           const SecAuthenticationType& auth_type,
     75                           const char* security_domain, const char* path,
     76                           const char* username, OSType creator) {
     77   // Allocate enough to hold everything we might use.
     78   const unsigned int kMaxEntryCount = 8;
     79   search_attributes_.attr =
     80       static_cast<SecKeychainAttribute*>(calloc(kMaxEntryCount,
     81                                                 sizeof(SecKeychainAttribute)));
     82   unsigned int entries = 0;
     83   // We only use search_attributes_ with SearchCreateFromAttributes, which takes
     84   // a "const SecKeychainAttributeList *", so we trust that they won't try
     85   // to modify the list, and that casting away const-ness is thus safe.
     86   if (server != NULL) {
     87     DCHECK_LT(entries, kMaxEntryCount);
     88     search_attributes_.attr[entries].tag = kSecServerItemAttr;
     89     search_attributes_.attr[entries].length = strlen(server);
     90     search_attributes_.attr[entries].data =
     91         const_cast<void*>(reinterpret_cast<const void*>(server));
     92     ++entries;
     93   }
     94   if (port != kAnyPort) {
     95     DCHECK_LE(entries, kMaxEntryCount);
     96     search_attributes_.attr[entries].tag = kSecPortItemAttr;
     97     search_attributes_.attr[entries].length = sizeof(port);
     98     search_attributes_.attr[entries].data =
     99         const_cast<void*>(reinterpret_cast<const void*>(&port));
    100     ++entries;
    101   }
    102   if (protocol != kSecProtocolTypeAny) {
    103     DCHECK_LE(entries, kMaxEntryCount);
    104     search_attributes_.attr[entries].tag = kSecProtocolItemAttr;
    105     search_attributes_.attr[entries].length = sizeof(protocol);
    106     search_attributes_.attr[entries].data =
    107         const_cast<void*>(reinterpret_cast<const void*>(&protocol));
    108     ++entries;
    109   }
    110   if (auth_type != kSecAuthenticationTypeAny) {
    111     DCHECK_LE(entries, kMaxEntryCount);
    112     search_attributes_.attr[entries].tag = kSecAuthenticationTypeItemAttr;
    113     search_attributes_.attr[entries].length = sizeof(auth_type);
    114     search_attributes_.attr[entries].data =
    115         const_cast<void*>(reinterpret_cast<const void*>(&auth_type));
    116     ++entries;
    117   }
    118   if (security_domain != NULL && strlen(security_domain) > 0) {
    119     DCHECK_LE(entries, kMaxEntryCount);
    120     search_attributes_.attr[entries].tag = kSecSecurityDomainItemAttr;
    121     search_attributes_.attr[entries].length = strlen(security_domain);
    122     search_attributes_.attr[entries].data =
    123         const_cast<void*>(reinterpret_cast<const void*>(security_domain));
    124     ++entries;
    125   }
    126   if (path != NULL && strlen(path) > 0 && strcmp(path, "/") != 0) {
    127     DCHECK_LE(entries, kMaxEntryCount);
    128     search_attributes_.attr[entries].tag = kSecPathItemAttr;
    129     search_attributes_.attr[entries].length = strlen(path);
    130     search_attributes_.attr[entries].data =
    131         const_cast<void*>(reinterpret_cast<const void*>(path));
    132     ++entries;
    133   }
    134   if (username != NULL) {
    135     DCHECK_LE(entries, kMaxEntryCount);
    136     search_attributes_.attr[entries].tag = kSecAccountItemAttr;
    137     search_attributes_.attr[entries].length = strlen(username);
    138     search_attributes_.attr[entries].data =
    139         const_cast<void*>(reinterpret_cast<const void*>(username));
    140     ++entries;
    141   }
    142   if (creator != 0) {
    143     DCHECK_LE(entries, kMaxEntryCount);
    144     search_attributes_.attr[entries].tag = kSecCreatorItemAttr;
    145     search_attributes_.attr[entries].length = sizeof(creator);
    146     search_attributes_.attr[entries].data =
    147         const_cast<void*>(reinterpret_cast<const void*>(&creator));
    148     ++entries;
    149   }
    150   search_attributes_.count = entries;
    151 }
    152 
    153 void KeychainSearch::FindMatchingItems(std::vector<SecKeychainItemRef>* items) {
    154   OSStatus result = keychain_->SearchCreateFromAttributes(
    155       NULL, kSecInternetPasswordItemClass, &search_attributes_, &search_ref_);
    156 
    157   if (result != noErr) {
    158     OSSTATUS_LOG(ERROR, result) << "Keychain lookup failed";
    159     return;
    160   }
    161 
    162   SecKeychainItemRef keychain_item;
    163   while (keychain_->SearchCopyNext(search_ref_, &keychain_item) == noErr) {
    164     // Consumer is responsible for freeing the items.
    165     items->push_back(keychain_item);
    166   }
    167 
    168   keychain_->Free(search_ref_);
    169   search_ref_ = NULL;
    170 }
    171 
    172 #pragma mark -
    173 
    174 // TODO(stuartmorgan): Convert most of this to private helpers in
    175 // MacKeychainPasswordFormAdapter once it has sufficient higher-level public
    176 // methods to provide test coverage.
    177 namespace internal_keychain_helpers {
    178 
    179 // Returns a URL built from the given components. To create a URL without a
    180 // port, pass kAnyPort for the |port| parameter.
    181 GURL URLFromComponents(bool is_secure, const std::string& host, int port,
    182                        const std::string& path) {
    183   GURL::Replacements url_components;
    184   std::string scheme(is_secure ? "https" : "http");
    185   url_components.SetSchemeStr(scheme);
    186   url_components.SetHostStr(host);
    187   std::string port_string;  // Must remain in scope until after we do replacing.
    188   if (port != kAnyPort) {
    189     std::ostringstream port_stringstream;
    190     port_stringstream << port;
    191     port_string = port_stringstream.str();
    192     url_components.SetPortStr(port_string);
    193   }
    194   url_components.SetPathStr(path);
    195 
    196   GURL url("http://dummy.com");  // ReplaceComponents needs a valid URL.
    197   return url.ReplaceComponents(url_components);
    198 }
    199 
    200 // Converts a Keychain time string to a Time object, returning true if
    201 // time_string_bytes was parsable. If the return value is false, the value of
    202 // |time| is unchanged.
    203 bool TimeFromKeychainTimeString(const char* time_string_bytes,
    204                                 unsigned int byte_length,
    205                                 base::Time* time) {
    206   DCHECK(time);
    207 
    208   char* time_string = static_cast<char*>(malloc(byte_length + 1));
    209   memcpy(time_string, time_string_bytes, byte_length);
    210   time_string[byte_length] = '\0';
    211   base::Time::Exploded exploded_time;
    212   bzero(&exploded_time, sizeof(exploded_time));
    213   // The time string is of the form "yyyyMMddHHmmss'Z", in UTC time.
    214   int assignments = sscanf(time_string, "%4d%2d%2d%2d%2d%2dZ",
    215                            &exploded_time.year, &exploded_time.month,
    216                            &exploded_time.day_of_month, &exploded_time.hour,
    217                            &exploded_time.minute, &exploded_time.second);
    218   free(time_string);
    219 
    220   if (assignments == 6) {
    221     *time = base::Time::FromUTCExploded(exploded_time);
    222     return true;
    223   }
    224   return false;
    225 }
    226 
    227 // Returns the PasswordForm Scheme corresponding to |auth_type|.
    228 PasswordForm::Scheme SchemeForAuthType(SecAuthenticationType auth_type) {
    229   switch (auth_type) {
    230     case kSecAuthenticationTypeHTMLForm:   return PasswordForm::SCHEME_HTML;
    231     case kSecAuthenticationTypeHTTPBasic:  return PasswordForm::SCHEME_BASIC;
    232     case kSecAuthenticationTypeHTTPDigest: return PasswordForm::SCHEME_DIGEST;
    233     default:                               return PasswordForm::SCHEME_OTHER;
    234   }
    235 }
    236 
    237 bool FillPasswordFormFromKeychainItem(const AppleKeychain& keychain,
    238                                       const SecKeychainItemRef& keychain_item,
    239                                       PasswordForm* form,
    240                                       bool extract_password_data) {
    241   DCHECK(form);
    242 
    243   SecKeychainAttributeInfo attrInfo;
    244   UInt32 tags[] = { kSecAccountItemAttr,
    245                     kSecServerItemAttr,
    246                     kSecPortItemAttr,
    247                     kSecPathItemAttr,
    248                     kSecProtocolItemAttr,
    249                     kSecAuthenticationTypeItemAttr,
    250                     kSecSecurityDomainItemAttr,
    251                     kSecCreationDateItemAttr,
    252                     kSecNegativeItemAttr };
    253   attrInfo.count = arraysize(tags);
    254   attrInfo.tag = tags;
    255   attrInfo.format = NULL;
    256 
    257   SecKeychainAttributeList *attrList;
    258   UInt32 password_length;
    259 
    260   // If |extract_password_data| is false, do not pass in a reference to
    261   // |password_data|. ItemCopyAttributesAndData will then extract only the
    262   // attributes of |keychain_item| (doesn't require OS authorization), and not
    263   // attempt to extract its password data (requires OS authorization).
    264   void* password_data = NULL;
    265   void** password_data_ref = extract_password_data ? &password_data : NULL;
    266 
    267   OSStatus result = keychain.ItemCopyAttributesAndData(keychain_item, &attrInfo,
    268                                                        NULL, &attrList,
    269                                                        &password_length,
    270                                                        password_data_ref);
    271 
    272   if (result != noErr) {
    273     // We don't log errSecAuthFailed because that just means that the user
    274     // chose not to allow us access to the item.
    275     if (result != errSecAuthFailed) {
    276       OSSTATUS_LOG(ERROR, result) << "Keychain data load failed";
    277     }
    278     return false;
    279   }
    280 
    281   if (extract_password_data) {
    282     base::UTF8ToUTF16(static_cast<const char *>(password_data), password_length,
    283                       &(form->password_value));
    284   }
    285 
    286   int port = kAnyPort;
    287   std::string server;
    288   std::string security_domain;
    289   std::string path;
    290   for (unsigned int i = 0; i < attrList->count; i++) {
    291     SecKeychainAttribute attr = attrList->attr[i];
    292     if (!attr.data) {
    293       continue;
    294     }
    295     switch (attr.tag) {
    296       case kSecAccountItemAttr:
    297         base::UTF8ToUTF16(static_cast<const char *>(attr.data), attr.length,
    298                           &(form->username_value));
    299         break;
    300       case kSecServerItemAttr:
    301         server.assign(static_cast<const char *>(attr.data), attr.length);
    302         break;
    303       case kSecPortItemAttr:
    304         port = *(static_cast<UInt32*>(attr.data));
    305         break;
    306       case kSecPathItemAttr:
    307         path.assign(static_cast<const char *>(attr.data), attr.length);
    308         break;
    309       case kSecProtocolItemAttr:
    310       {
    311         SecProtocolType protocol = *(static_cast<SecProtocolType*>(attr.data));
    312         // TODO(stuartmorgan): Handle proxy types
    313         form->ssl_valid = (protocol == kSecProtocolTypeHTTPS);
    314         break;
    315       }
    316       case kSecAuthenticationTypeItemAttr:
    317       {
    318         SecAuthenticationType auth_type =
    319             *(static_cast<SecAuthenticationType*>(attr.data));
    320         form->scheme = SchemeForAuthType(auth_type);
    321         break;
    322       }
    323       case kSecSecurityDomainItemAttr:
    324         security_domain.assign(static_cast<const char *>(attr.data),
    325                                attr.length);
    326         break;
    327       case kSecCreationDateItemAttr:
    328         // The only way to get a date out of Keychain is as a string. Really.
    329         // (The docs claim it's an int, but the header is correct.)
    330         TimeFromKeychainTimeString(static_cast<char*>(attr.data), attr.length,
    331                                    &form->date_created);
    332         break;
    333       case kSecNegativeItemAttr:
    334         Boolean negative_item = *(static_cast<Boolean*>(attr.data));
    335         if (negative_item) {
    336           form->blacklisted_by_user = true;
    337         }
    338         break;
    339     }
    340   }
    341   keychain.ItemFreeAttributesAndData(attrList, password_data);
    342 
    343   // kSecNegativeItemAttr doesn't seem to actually be in widespread use. In
    344   // practice, other browsers seem to use a "" or " " password (and a special
    345   // user name) to indicated blacklist entries.
    346   if (extract_password_data && (form->password_value.empty() ||
    347                                 EqualsASCII(form->password_value, " "))) {
    348     form->blacklisted_by_user = true;
    349   }
    350 
    351   form->origin = URLFromComponents(form->ssl_valid, server, port, path);
    352   // TODO(stuartmorgan): Handle proxies, which need a different signon_realm
    353   // format.
    354   form->signon_realm = form->origin.GetOrigin().spec();
    355   if (form->scheme != PasswordForm::SCHEME_HTML) {
    356     form->signon_realm.append(security_domain);
    357   }
    358   return true;
    359 }
    360 
    361 bool FormsMatchForMerge(const PasswordForm& form_a,
    362                         const PasswordForm& form_b,
    363                         FormMatchStrictness strictness) {
    364   // We never merge blacklist entries between our store and the keychain.
    365   if (form_a.blacklisted_by_user || form_b.blacklisted_by_user) {
    366     return false;
    367   }
    368   bool equal_realm = form_a.signon_realm == form_b.signon_realm;
    369   if (strictness == FUZZY_FORM_MATCH) {
    370     equal_realm |= (!form_a.original_signon_realm.empty()) &&
    371                    form_a.original_signon_realm == form_b.signon_realm;
    372   }
    373   return form_a.scheme == form_b.scheme && equal_realm &&
    374          form_a.username_value == form_b.username_value;
    375 }
    376 
    377 // Returns an the best match for |base_form| from |keychain_forms|, or NULL if
    378 // there is no suitable match.
    379 PasswordForm* BestKeychainFormForForm(
    380     const PasswordForm& base_form,
    381     const std::vector<PasswordForm*>* keychain_forms) {
    382   PasswordForm* partial_match = NULL;
    383   for (std::vector<PasswordForm*>::const_iterator i = keychain_forms->begin();
    384        i != keychain_forms->end(); ++i) {
    385     // TODO(stuartmorgan): We should really be scoring path matches and picking
    386     // the best, rather than just checking exact-or-not (although in practice
    387     // keychain items with paths probably came from us).
    388     if (FormsMatchForMerge(base_form, *(*i), FUZZY_FORM_MATCH)) {
    389       if (base_form.origin == (*i)->origin) {
    390         return *i;
    391       } else if (!partial_match) {
    392         partial_match = *i;
    393       }
    394     }
    395   }
    396   return partial_match;
    397 }
    398 
    399 // Returns entries from |forms| that are blacklist entries, after removing
    400 // them from |forms|.
    401 std::vector<PasswordForm*> ExtractBlacklistForms(
    402     std::vector<PasswordForm*>* forms) {
    403   std::vector<PasswordForm*> blacklist_forms;
    404   for (std::vector<PasswordForm*>::iterator i = forms->begin();
    405        i != forms->end();) {
    406     PasswordForm* form = *i;
    407     if (form->blacklisted_by_user) {
    408       blacklist_forms.push_back(form);
    409       i = forms->erase(i);
    410     } else {
    411       ++i;
    412     }
    413   }
    414   return blacklist_forms;
    415 }
    416 
    417 // Deletes and removes from v any element that exists in s.
    418 template <class T>
    419 void DeleteVectorElementsInSet(std::vector<T*>* v, const std::set<T*>& s) {
    420   for (typename std::vector<T*>::iterator i = v->begin(); i != v->end();) {
    421     T* element = *i;
    422     if (s.find(element) != s.end()) {
    423       delete element;
    424       i = v->erase(i);
    425     } else {
    426       ++i;
    427     }
    428   }
    429 }
    430 
    431 void MergePasswordForms(std::vector<PasswordForm*>* keychain_forms,
    432                         std::vector<PasswordForm*>* database_forms,
    433                         std::vector<PasswordForm*>* merged_forms) {
    434   // Pull out the database blacklist items, since they are used as-is rather
    435   // than being merged with keychain forms.
    436   std::vector<PasswordForm*> database_blacklist_forms =
    437       ExtractBlacklistForms(database_forms);
    438 
    439   // Merge the normal entries.
    440   std::set<PasswordForm*> used_keychain_forms;
    441   for (std::vector<PasswordForm*>::iterator i = database_forms->begin();
    442        i != database_forms->end();) {
    443     PasswordForm* db_form = *i;
    444     PasswordForm* best_match = BestKeychainFormForForm(*db_form,
    445                                                        keychain_forms);
    446     if (best_match) {
    447       used_keychain_forms.insert(best_match);
    448       db_form->password_value = best_match->password_value;
    449       merged_forms->push_back(db_form);
    450       i = database_forms->erase(i);
    451     } else {
    452       ++i;
    453     }
    454   }
    455 
    456   // Add in the blacklist entries from the database.
    457   merged_forms->insert(merged_forms->end(),
    458                        database_blacklist_forms.begin(),
    459                        database_blacklist_forms.end());
    460 
    461   // Clear out all the Keychain entries we used.
    462   DeleteVectorElementsInSet(keychain_forms, used_keychain_forms);
    463 }
    464 
    465 std::vector<ItemFormPair> ExtractAllKeychainItemAttributesIntoPasswordForms(
    466     std::vector<SecKeychainItemRef>* keychain_items,
    467     const AppleKeychain& keychain) {
    468   DCHECK(keychain_items);
    469   MacKeychainPasswordFormAdapter keychain_adapter(&keychain);
    470   *keychain_items = keychain_adapter.GetAllPasswordFormKeychainItems();
    471   std::vector<ItemFormPair> item_form_pairs;
    472   for (std::vector<SecKeychainItemRef>::iterator i = keychain_items->begin();
    473        i != keychain_items->end(); ++i) {
    474     PasswordForm* form_without_password = new PasswordForm();
    475     internal_keychain_helpers::FillPasswordFormFromKeychainItem(
    476         keychain,
    477         *i,
    478         form_without_password,
    479         false);  // Load password attributes, but not password data.
    480     item_form_pairs.push_back(std::make_pair(&(*i), form_without_password));
    481   }
    482   return item_form_pairs;
    483 }
    484 
    485 std::vector<PasswordForm*> GetPasswordsForForms(
    486     const AppleKeychain& keychain,
    487     std::vector<PasswordForm*>* database_forms) {
    488   // First load the attributes of all items in the keychain without loading
    489   // their password data, and then match items in |database_forms| against them.
    490   // This avoids individually searching through the keychain for passwords
    491   // matching each form in |database_forms|, and results in a significant
    492   // performance gain, replacing O(N) keychain search operations with a single
    493   // operation that loads all keychain items, and then selective reads of only
    494   // the relevant passwords. See crbug.com/263685.
    495   std::vector<SecKeychainItemRef> keychain_items;
    496   std::vector<ItemFormPair> item_form_pairs =
    497       ExtractAllKeychainItemAttributesIntoPasswordForms(&keychain_items,
    498                                                         keychain);
    499 
    500   // Next, compare the attributes of the PasswordForms in |database_forms|
    501   // against those in |item_form_pairs|, and extract password data for each
    502   // matching PasswordForm using its corresponding SecKeychainItemRef.
    503   std::vector<PasswordForm*> merged_forms;
    504   for (std::vector<PasswordForm*>::iterator i = database_forms->begin();
    505        i != database_forms->end();) {
    506     std::vector<PasswordForm*> db_form_container(1, *i);
    507     std::vector<PasswordForm*> keychain_matches =
    508         ExtractPasswordsMergeableWithForm(keychain, item_form_pairs, **i);
    509     MergePasswordForms(&keychain_matches, &db_form_container, &merged_forms);
    510     if (db_form_container.empty()) {
    511       i = database_forms->erase(i);
    512     } else {
    513       ++i;
    514     }
    515     STLDeleteElements(&keychain_matches);
    516   }
    517 
    518   // Clean up temporary PasswordForms and SecKeychainItemRefs.
    519   STLDeleteContainerPairSecondPointers(item_form_pairs.begin(),
    520                                        item_form_pairs.end());
    521   for (std::vector<SecKeychainItemRef>::iterator i = keychain_items.begin();
    522        i != keychain_items.end(); ++i) {
    523     keychain.Free(*i);
    524   }
    525   return merged_forms;
    526 }
    527 
    528 // TODO(stuartmorgan): signon_realm for proxies is not yet supported.
    529 bool ExtractSignonRealmComponents(
    530     const std::string& signon_realm, std::string* server, int* port,
    531     bool* is_secure, std::string* security_domain) {
    532   // The signon_realm will be the Origin portion of a URL for an HTML form,
    533   // and the same but with the security domain as a path for HTTP auth.
    534   GURL realm_as_url(signon_realm);
    535   if (!realm_as_url.is_valid()) {
    536     return false;
    537   }
    538 
    539   if (server)
    540     *server = realm_as_url.host();
    541   if (is_secure)
    542     *is_secure = realm_as_url.SchemeIsSecure();
    543   if (port)
    544     *port = realm_as_url.has_port() ? atoi(realm_as_url.port().c_str()) : 0;
    545   if (security_domain) {
    546     // Strip the leading '/' off of the path to get the security domain.
    547     if (realm_as_url.path().length() > 0)
    548       *security_domain = realm_as_url.path().substr(1);
    549     else
    550       security_domain->clear();
    551   }
    552   return true;
    553 }
    554 
    555 bool FormIsValidAndMatchesOtherForm(const PasswordForm& query_form,
    556                                     const PasswordForm& other_form) {
    557   std::string server;
    558   std::string security_domain;
    559   int port;
    560   bool is_secure;
    561   if (!ExtractSignonRealmComponents(query_form.signon_realm, &server, &port,
    562                                     &is_secure, &security_domain)) {
    563     return false;
    564   }
    565   return internal_keychain_helpers::FormsMatchForMerge(
    566       query_form, other_form, STRICT_FORM_MATCH);
    567 }
    568 
    569 std::vector<PasswordForm*> ExtractPasswordsMergeableWithForm(
    570     const AppleKeychain& keychain,
    571     const std::vector<ItemFormPair>& item_form_pairs,
    572     const PasswordForm& query_form) {
    573   std::vector<PasswordForm*> matches;
    574   for (std::vector<ItemFormPair>::const_iterator i = item_form_pairs.begin();
    575        i != item_form_pairs.end(); ++i) {
    576     if (FormIsValidAndMatchesOtherForm(query_form, *(i->second))) {
    577       // Create a new object, since the caller is responsible for deleting the
    578       // returned forms.
    579       scoped_ptr<PasswordForm> form_with_password(new PasswordForm());
    580       internal_keychain_helpers::FillPasswordFormFromKeychainItem(
    581           keychain,
    582           *(i->first),
    583           form_with_password.get(),
    584           true);  // Load password attributes and data.
    585       // Do not include blacklisted items found in the keychain.
    586       if (!form_with_password->blacklisted_by_user)
    587         matches.push_back(form_with_password.release());
    588     }
    589   }
    590   return matches;
    591 }
    592 
    593 }  // namespace internal_keychain_helpers
    594 
    595 #pragma mark -
    596 
    597 MacKeychainPasswordFormAdapter::MacKeychainPasswordFormAdapter(
    598     const AppleKeychain* keychain)
    599     : keychain_(keychain), finds_only_owned_(false) {
    600 }
    601 
    602 std::vector<PasswordForm*> MacKeychainPasswordFormAdapter::PasswordsFillingForm(
    603     const std::string& signon_realm,
    604     PasswordForm::Scheme scheme) {
    605   std::vector<SecKeychainItemRef> keychain_items =
    606       MatchingKeychainItems(signon_realm, scheme, NULL, NULL);
    607 
    608   return ConvertKeychainItemsToForms(&keychain_items);
    609 }
    610 
    611 PasswordForm* MacKeychainPasswordFormAdapter::PasswordExactlyMatchingForm(
    612     const PasswordForm& query_form) {
    613   SecKeychainItemRef keychain_item = KeychainItemForForm(query_form);
    614   if (keychain_item) {
    615     PasswordForm* form = new PasswordForm();
    616     internal_keychain_helpers::FillPasswordFormFromKeychainItem(*keychain_,
    617                                                                 keychain_item,
    618                                                                 form,
    619                                                                 true);
    620     keychain_->Free(keychain_item);
    621     return form;
    622   }
    623   return NULL;
    624 }
    625 
    626 bool MacKeychainPasswordFormAdapter::HasPasswordsMergeableWithForm(
    627     const PasswordForm& query_form) {
    628   std::string username = base::UTF16ToUTF8(query_form.username_value);
    629   std::vector<SecKeychainItemRef> matches =
    630       MatchingKeychainItems(query_form.signon_realm, query_form.scheme,
    631                             NULL, username.c_str());
    632   for (std::vector<SecKeychainItemRef>::iterator i = matches.begin();
    633        i != matches.end(); ++i) {
    634     keychain_->Free(*i);
    635   }
    636 
    637   return !matches.empty();
    638 }
    639 
    640 std::vector<SecKeychainItemRef>
    641     MacKeychainPasswordFormAdapter::GetAllPasswordFormKeychainItems() {
    642   SecAuthenticationType supported_auth_types[] = {
    643     kSecAuthenticationTypeHTMLForm,
    644     kSecAuthenticationTypeHTTPBasic,
    645     kSecAuthenticationTypeHTTPDigest,
    646   };
    647 
    648   std::vector<SecKeychainItemRef> matches;
    649   for (unsigned int i = 0; i < arraysize(supported_auth_types); ++i) {
    650     KeychainSearch keychain_search(*keychain_);
    651     keychain_search.Init(NULL, 0, kSecProtocolTypeAny, supported_auth_types[i],
    652                          NULL, NULL, NULL, CreatorCodeForSearch());
    653     keychain_search.FindMatchingItems(&matches);
    654   }
    655   return matches;
    656 }
    657 
    658 std::vector<PasswordForm*>
    659     MacKeychainPasswordFormAdapter::GetAllPasswordFormPasswords() {
    660   std::vector<SecKeychainItemRef> items = GetAllPasswordFormKeychainItems();
    661   return ConvertKeychainItemsToForms(&items);
    662 }
    663 
    664 bool MacKeychainPasswordFormAdapter::AddPassword(const PasswordForm& form) {
    665   // We should never be trying to store a blacklist in the keychain.
    666   DCHECK(!form.blacklisted_by_user);
    667 
    668   std::string server;
    669   std::string security_domain;
    670   int port;
    671   bool is_secure;
    672   if (!internal_keychain_helpers::ExtractSignonRealmComponents(
    673            form.signon_realm, &server, &port, &is_secure, &security_domain)) {
    674     return false;
    675   }
    676   std::string username = base::UTF16ToUTF8(form.username_value);
    677   std::string password = base::UTF16ToUTF8(form.password_value);
    678   std::string path = form.origin.path();
    679   SecProtocolType protocol = is_secure ? kSecProtocolTypeHTTPS
    680                                        : kSecProtocolTypeHTTP;
    681   SecKeychainItemRef new_item = NULL;
    682   OSStatus result = keychain_->AddInternetPassword(
    683       NULL, server.size(), server.c_str(),
    684       security_domain.size(), security_domain.c_str(),
    685       username.size(), username.c_str(),
    686       path.size(), path.c_str(),
    687       port, protocol, AuthTypeForScheme(form.scheme),
    688       password.size(), password.c_str(), &new_item);
    689 
    690   if (result == noErr) {
    691     SetKeychainItemCreatorCode(new_item,
    692                                base::mac::CreatorCodeForApplication());
    693     keychain_->Free(new_item);
    694   } else if (result == errSecDuplicateItem) {
    695     // If we collide with an existing item, find and update it instead.
    696     SecKeychainItemRef existing_item = KeychainItemForForm(form);
    697     if (!existing_item) {
    698       return false;
    699     }
    700     bool changed = SetKeychainItemPassword(existing_item, password);
    701     keychain_->Free(existing_item);
    702     return changed;
    703   }
    704 
    705   return result == noErr;
    706 }
    707 
    708 bool MacKeychainPasswordFormAdapter::RemovePassword(const PasswordForm& form) {
    709   SecKeychainItemRef keychain_item = KeychainItemForForm(form);
    710   if (keychain_item == NULL)
    711     return false;
    712   OSStatus result = keychain_->ItemDelete(keychain_item);
    713   keychain_->Free(keychain_item);
    714   return result == noErr;
    715 }
    716 
    717 void MacKeychainPasswordFormAdapter::SetFindsOnlyOwnedItems(
    718     bool finds_only_owned) {
    719   finds_only_owned_ = finds_only_owned;
    720 }
    721 
    722 std::vector<PasswordForm*>
    723     MacKeychainPasswordFormAdapter::ConvertKeychainItemsToForms(
    724         std::vector<SecKeychainItemRef>* items) {
    725   std::vector<PasswordForm*> keychain_forms;
    726   for (std::vector<SecKeychainItemRef>::const_iterator i = items->begin();
    727        i != items->end(); ++i) {
    728     PasswordForm* form = new PasswordForm();
    729     if (internal_keychain_helpers::FillPasswordFormFromKeychainItem(
    730             *keychain_, *i, form, true)) {
    731       keychain_forms.push_back(form);
    732     }
    733     keychain_->Free(*i);
    734   }
    735   items->clear();
    736   return keychain_forms;
    737 }
    738 
    739 SecKeychainItemRef MacKeychainPasswordFormAdapter::KeychainItemForForm(
    740     const PasswordForm& form) {
    741   // We don't store blacklist entries in the keychain, so the answer to "what
    742   // Keychain item goes with this form" is always "nothing" for blacklists.
    743   if (form.blacklisted_by_user) {
    744     return NULL;
    745   }
    746 
    747   std::string path = form.origin.path();
    748   std::string username = base::UTF16ToUTF8(form.username_value);
    749   std::vector<SecKeychainItemRef> matches = MatchingKeychainItems(
    750       form.signon_realm, form.scheme, path.c_str(), username.c_str());
    751 
    752   if (matches.empty()) {
    753     return NULL;
    754   }
    755   // Free all items after the first, since we won't be returning them.
    756   for (std::vector<SecKeychainItemRef>::iterator i = matches.begin() + 1;
    757        i != matches.end(); ++i) {
    758     keychain_->Free(*i);
    759   }
    760   return matches[0];
    761 }
    762 
    763 std::vector<SecKeychainItemRef>
    764     MacKeychainPasswordFormAdapter::MatchingKeychainItems(
    765         const std::string& signon_realm,
    766         autofill::PasswordForm::Scheme scheme,
    767         const char* path, const char* username) {
    768   std::vector<SecKeychainItemRef> matches;
    769 
    770   std::string server;
    771   std::string security_domain;
    772   int port;
    773   bool is_secure;
    774   if (!internal_keychain_helpers::ExtractSignonRealmComponents(
    775            signon_realm, &server, &port, &is_secure, &security_domain)) {
    776     // TODO(stuartmorgan): Proxies will currently fail here, since their
    777     // signon_realm is not a URL. We need to detect the proxy case and handle
    778     // it specially.
    779     return matches;
    780   }
    781   SecProtocolType protocol = is_secure ? kSecProtocolTypeHTTPS
    782                                        : kSecProtocolTypeHTTP;
    783   SecAuthenticationType auth_type = AuthTypeForScheme(scheme);
    784   const char* auth_domain = (scheme == PasswordForm::SCHEME_HTML) ?
    785       NULL : security_domain.c_str();
    786   KeychainSearch keychain_search(*keychain_);
    787   keychain_search.Init(server.c_str(), port, protocol, auth_type,
    788                        auth_domain, path, username, CreatorCodeForSearch());
    789   keychain_search.FindMatchingItems(&matches);
    790   return matches;
    791 }
    792 
    793 // Returns the Keychain SecAuthenticationType type corresponding to |scheme|.
    794 SecAuthenticationType MacKeychainPasswordFormAdapter::AuthTypeForScheme(
    795     PasswordForm::Scheme scheme) {
    796   switch (scheme) {
    797     case PasswordForm::SCHEME_HTML:   return kSecAuthenticationTypeHTMLForm;
    798     case PasswordForm::SCHEME_BASIC:  return kSecAuthenticationTypeHTTPBasic;
    799     case PasswordForm::SCHEME_DIGEST: return kSecAuthenticationTypeHTTPDigest;
    800     case PasswordForm::SCHEME_OTHER:  return kSecAuthenticationTypeDefault;
    801   }
    802   NOTREACHED();
    803   return kSecAuthenticationTypeDefault;
    804 }
    805 
    806 bool MacKeychainPasswordFormAdapter::SetKeychainItemPassword(
    807     const SecKeychainItemRef& keychain_item, const std::string& password) {
    808   OSStatus result = keychain_->ItemModifyAttributesAndData(keychain_item, NULL,
    809                                                            password.size(),
    810                                                            password.c_str());
    811   return result == noErr;
    812 }
    813 
    814 bool MacKeychainPasswordFormAdapter::SetKeychainItemCreatorCode(
    815     const SecKeychainItemRef& keychain_item, OSType creator_code) {
    816   SecKeychainAttribute attr = { kSecCreatorItemAttr, sizeof(creator_code),
    817                                 &creator_code };
    818   SecKeychainAttributeList attrList = { 1, &attr };
    819   OSStatus result = keychain_->ItemModifyAttributesAndData(keychain_item,
    820                                                            &attrList, 0, NULL);
    821   return result == noErr;
    822 }
    823 
    824 OSType MacKeychainPasswordFormAdapter::CreatorCodeForSearch() {
    825   return finds_only_owned_ ? base::mac::CreatorCodeForApplication() : 0;
    826 }
    827 
    828 #pragma mark -
    829 
    830 PasswordStoreMac::PasswordStoreMac(
    831     scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner,
    832     scoped_refptr<base::SingleThreadTaskRunner> db_thread_runner,
    833     AppleKeychain* keychain,
    834     password_manager::LoginDatabase* login_db)
    835     : password_manager::PasswordStore(main_thread_runner, db_thread_runner),
    836       keychain_(keychain),
    837       login_metadata_db_(login_db) {
    838   DCHECK(keychain_.get());
    839   DCHECK(login_metadata_db_.get());
    840 }
    841 
    842 PasswordStoreMac::~PasswordStoreMac() {}
    843 
    844 bool PasswordStoreMac::Init(
    845     const syncer::SyncableService::StartSyncFlare& flare) {
    846   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
    847   thread_.reset(new base::Thread("Chrome_PasswordStore_Thread"));
    848 
    849   if (!thread_->Start()) {
    850     thread_.reset(NULL);
    851     return false;
    852   }
    853   return password_manager::PasswordStore::Init(flare);
    854 }
    855 
    856 void PasswordStoreMac::Shutdown() {
    857   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
    858   password_manager::PasswordStore::Shutdown();
    859   thread_->Stop();
    860 }
    861 
    862 // Mac stores passwords in the system keychain, which can block for an
    863 // arbitrarily long time (most notably, it can block on user confirmation
    864 // from a dialog). Run tasks on a dedicated thread to avoid blocking the DB
    865 // thread.
    866 scoped_refptr<base::SingleThreadTaskRunner>
    867 PasswordStoreMac::GetBackgroundTaskRunner() {
    868   return (thread_.get()) ? thread_->message_loop_proxy() : NULL;
    869 }
    870 
    871 void PasswordStoreMac::ReportMetricsImpl() {
    872   login_metadata_db_->ReportMetrics();
    873 }
    874 
    875 PasswordStoreChangeList PasswordStoreMac::AddLoginImpl(
    876     const PasswordForm& form) {
    877   DCHECK(thread_->message_loop() == base::MessageLoop::current());
    878   PasswordStoreChangeList changes;
    879   if (AddToKeychainIfNecessary(form)) {
    880     changes = login_metadata_db_->AddLogin(form);
    881   }
    882   return changes;
    883 }
    884 
    885 PasswordStoreChangeList PasswordStoreMac::UpdateLoginImpl(
    886     const PasswordForm& form) {
    887   DCHECK(thread_->message_loop() == base::MessageLoop::current());
    888   PasswordStoreChangeList changes = login_metadata_db_->UpdateLogin(form);
    889 
    890   MacKeychainPasswordFormAdapter keychain_adapter(keychain_.get());
    891   if (changes.empty() &&
    892       !keychain_adapter.HasPasswordsMergeableWithForm(form)) {
    893     // If the password isn't in either the DB or the keychain, then it must have
    894     // been deleted after autofill happened, and should not be re-added.
    895     return changes;
    896   }
    897 
    898   // The keychain add will update if there is a collision and add if there
    899   // isn't, which is the behavior we want, so there's no separate update call.
    900   if (AddToKeychainIfNecessary(form) && changes.empty()) {
    901     changes = login_metadata_db_->AddLogin(form);
    902   }
    903   return changes;
    904 }
    905 
    906 PasswordStoreChangeList PasswordStoreMac::RemoveLoginImpl(
    907     const PasswordForm& form) {
    908   DCHECK(thread_->message_loop() == base::MessageLoop::current());
    909   PasswordStoreChangeList changes;
    910   if (login_metadata_db_->RemoveLogin(form)) {
    911     // See if we own a Keychain item associated with this item. We can do an
    912     // exact search rather than messing around with trying to do fuzzy matching
    913     // because passwords that we created will always have an exact-match
    914     // database entry.
    915     // (If a user does lose their profile but not their keychain we'll treat the
    916     // entries we find like other imported entries anyway, so it's reasonable to
    917     // handle deletes on them the way we would for an imported item.)
    918     MacKeychainPasswordFormAdapter owned_keychain_adapter(keychain_.get());
    919     owned_keychain_adapter.SetFindsOnlyOwnedItems(true);
    920     PasswordForm* owned_password_form =
    921         owned_keychain_adapter.PasswordExactlyMatchingForm(form);
    922     if (owned_password_form) {
    923       // If we don't have other forms using it (i.e., a form differing only by
    924       // the names of the form elements), delete the keychain entry.
    925       if (!DatabaseHasFormMatchingKeychainForm(form)) {
    926         owned_keychain_adapter.RemovePassword(form);
    927       }
    928     }
    929 
    930     changes.push_back(PasswordStoreChange(PasswordStoreChange::REMOVE, form));
    931   }
    932   return changes;
    933 }
    934 
    935 PasswordStoreChangeList PasswordStoreMac::RemoveLoginsCreatedBetweenImpl(
    936     base::Time delete_begin,
    937     base::Time delete_end) {
    938   PasswordStoreChangeList changes;
    939   std::vector<PasswordForm*> forms;
    940   if (login_metadata_db_->GetLoginsCreatedBetween(delete_begin, delete_end,
    941                                                   &forms)) {
    942     if (login_metadata_db_->RemoveLoginsCreatedBetween(delete_begin,
    943                                                        delete_end)) {
    944       // We can't delete from the Keychain by date because we may be sharing
    945       // items with database entries that weren't in the delete range. Instead,
    946       // we find all the Keychain items we own but aren't using any more and
    947       // delete those.
    948       std::vector<PasswordForm*> orphan_keychain_forms =
    949           GetUnusedKeychainForms();
    950       // This is inefficient, since we have to re-look-up each keychain item
    951       // one at a time to delete it even though the search step already had a
    952       // list of Keychain item references. If this turns out to be noticeably
    953       // slow we'll need to rearchitect to allow the search and deletion steps
    954       // to share.
    955       RemoveKeychainForms(orphan_keychain_forms);
    956       STLDeleteElements(&orphan_keychain_forms);
    957 
    958       for (std::vector<PasswordForm*>::const_iterator it = forms.begin();
    959            it != forms.end(); ++it) {
    960         changes.push_back(PasswordStoreChange(PasswordStoreChange::REMOVE,
    961                                               **it));
    962       }
    963       LogStatsForBulkDeletion(changes.size());
    964     }
    965   }
    966   return changes;
    967 }
    968 
    969 PasswordStoreChangeList PasswordStoreMac::RemoveLoginsSyncedBetweenImpl(
    970     base::Time delete_begin,
    971     base::Time delete_end) {
    972   PasswordStoreChangeList changes;
    973   std::vector<PasswordForm*> forms;
    974   if (login_metadata_db_->GetLoginsSyncedBetween(
    975           delete_begin, delete_end, &forms)) {
    976     if (login_metadata_db_->RemoveLoginsSyncedBetween(delete_begin,
    977                                                       delete_end)) {
    978       // We can't delete from the Keychain by date because we may be sharing
    979       // items with database entries that weren't in the delete range. Instead,
    980       // we find all the Keychain items we own but aren't using any more and
    981       // delete those.
    982       std::vector<PasswordForm*> orphan_keychain_forms =
    983           GetUnusedKeychainForms();
    984       // This is inefficient, since we have to re-look-up each keychain item
    985       // one at a time to delete it even though the search step already had a
    986       // list of Keychain item references. If this turns out to be noticeably
    987       // slow we'll need to rearchitect to allow the search and deletion steps
    988       // to share.
    989       RemoveKeychainForms(orphan_keychain_forms);
    990       STLDeleteElements(&orphan_keychain_forms);
    991 
    992       for (std::vector<PasswordForm*>::const_iterator it = forms.begin();
    993            it != forms.end();
    994            ++it) {
    995         changes.push_back(
    996             PasswordStoreChange(PasswordStoreChange::REMOVE, **it));
    997       }
    998     }
    999   }
   1000   return changes;
   1001 }
   1002 
   1003 void PasswordStoreMac::GetLoginsImpl(
   1004     const autofill::PasswordForm& form,
   1005     AuthorizationPromptPolicy prompt_policy,
   1006     const ConsumerCallbackRunner& callback_runner) {
   1007   chrome::ScopedSecKeychainSetUserInteractionAllowed user_interaction_allowed(
   1008       prompt_policy == ALLOW_PROMPT);
   1009 
   1010   std::vector<PasswordForm*> database_forms;
   1011   login_metadata_db_->GetLogins(form, &database_forms);
   1012 
   1013   // Let's gather all signon realms we want to match with keychain entries.
   1014   std::set<std::string> realm_set;
   1015   realm_set.insert(form.signon_realm);
   1016   for (std::vector<PasswordForm*>::const_iterator db_form =
   1017            database_forms.begin();
   1018        db_form != database_forms.end();
   1019        ++db_form) {
   1020     // TODO(vabr): We should not be getting different schemes here.
   1021     // http://crbug.com/340112
   1022     if (form.scheme != (*db_form)->scheme)
   1023       continue;  // Forms with different schemes never match.
   1024     const std::string& original_singon_realm((*db_form)->original_signon_realm);
   1025     if (!original_singon_realm.empty())
   1026       realm_set.insert(original_singon_realm);
   1027   }
   1028   std::vector<PasswordForm*> keychain_forms;
   1029   for (std::set<std::string>::const_iterator realm = realm_set.begin();
   1030        realm != realm_set.end();
   1031        ++realm) {
   1032     MacKeychainPasswordFormAdapter keychain_adapter(keychain_.get());
   1033     std::vector<PasswordForm*> temp_keychain_forms =
   1034         keychain_adapter.PasswordsFillingForm(*realm, form.scheme);
   1035     keychain_forms.insert(keychain_forms.end(),
   1036                           temp_keychain_forms.begin(),
   1037                           temp_keychain_forms.end());
   1038   }
   1039 
   1040   std::vector<PasswordForm*> matched_forms;
   1041   internal_keychain_helpers::MergePasswordForms(&keychain_forms,
   1042                                                 &database_forms,
   1043                                                 &matched_forms);
   1044 
   1045   // Strip any blacklist entries out of the unused Keychain array, then take
   1046   // all the entries that are left (which we can use as imported passwords).
   1047   std::vector<PasswordForm*> keychain_blacklist_forms =
   1048       internal_keychain_helpers::ExtractBlacklistForms(&keychain_forms);
   1049   matched_forms.insert(matched_forms.end(),
   1050                        keychain_forms.begin(),
   1051                        keychain_forms.end());
   1052   keychain_forms.clear();
   1053   STLDeleteElements(&keychain_blacklist_forms);
   1054 
   1055   // Clean up any orphaned database entries.
   1056   RemoveDatabaseForms(database_forms);
   1057   STLDeleteElements(&database_forms);
   1058 
   1059   callback_runner.Run(matched_forms);
   1060 }
   1061 
   1062 void PasswordStoreMac::GetBlacklistLoginsImpl(GetLoginsRequest* request) {
   1063   FillBlacklistLogins(request->result());
   1064   ForwardLoginsResult(request);
   1065 }
   1066 
   1067 void PasswordStoreMac::GetAutofillableLoginsImpl(GetLoginsRequest* request) {
   1068   FillAutofillableLogins(request->result());
   1069   ForwardLoginsResult(request);
   1070 }
   1071 
   1072 bool PasswordStoreMac::FillAutofillableLogins(
   1073          std::vector<PasswordForm*>* forms) {
   1074   DCHECK(thread_->message_loop() == base::MessageLoop::current());
   1075 
   1076   std::vector<PasswordForm*> database_forms;
   1077   login_metadata_db_->GetAutofillableLogins(&database_forms);
   1078 
   1079   std::vector<PasswordForm*> merged_forms =
   1080       internal_keychain_helpers::GetPasswordsForForms(*keychain_,
   1081                                                       &database_forms);
   1082 
   1083   // Clean up any orphaned database entries.
   1084   RemoveDatabaseForms(database_forms);
   1085   STLDeleteElements(&database_forms);
   1086 
   1087   forms->insert(forms->end(), merged_forms.begin(), merged_forms.end());
   1088   return true;
   1089 }
   1090 
   1091 bool PasswordStoreMac::FillBlacklistLogins(
   1092          std::vector<PasswordForm*>* forms) {
   1093   DCHECK(thread_->message_loop() == base::MessageLoop::current());
   1094   return login_metadata_db_->GetBlacklistLogins(forms);
   1095 }
   1096 
   1097 bool PasswordStoreMac::AddToKeychainIfNecessary(const PasswordForm& form) {
   1098   if (form.blacklisted_by_user) {
   1099     return true;
   1100   }
   1101   MacKeychainPasswordFormAdapter keychainAdapter(keychain_.get());
   1102   return keychainAdapter.AddPassword(form);
   1103 }
   1104 
   1105 bool PasswordStoreMac::DatabaseHasFormMatchingKeychainForm(
   1106     const autofill::PasswordForm& form) {
   1107   bool has_match = false;
   1108   std::vector<PasswordForm*> database_forms;
   1109   login_metadata_db_->GetLogins(form, &database_forms);
   1110   for (std::vector<PasswordForm*>::iterator i = database_forms.begin();
   1111        i != database_forms.end(); ++i) {
   1112     // Below we filter out forms with non-empty original_signon_realm, because
   1113     // those signal fuzzy matches, and we are only interested in exact ones.
   1114     if ((*i)->original_signon_realm.empty() &&
   1115         internal_keychain_helpers::FormsMatchForMerge(
   1116             form, **i, internal_keychain_helpers::STRICT_FORM_MATCH) &&
   1117         (*i)->origin == form.origin) {
   1118       has_match = true;
   1119       break;
   1120     }
   1121   }
   1122   STLDeleteElements(&database_forms);
   1123   return has_match;
   1124 }
   1125 
   1126 std::vector<PasswordForm*> PasswordStoreMac::GetUnusedKeychainForms() {
   1127   std::vector<PasswordForm*> database_forms;
   1128   login_metadata_db_->GetAutofillableLogins(&database_forms);
   1129 
   1130   MacKeychainPasswordFormAdapter owned_keychain_adapter(keychain_.get());
   1131   owned_keychain_adapter.SetFindsOnlyOwnedItems(true);
   1132   std::vector<PasswordForm*> owned_keychain_forms =
   1133       owned_keychain_adapter.GetAllPasswordFormPasswords();
   1134 
   1135   // Run a merge; anything left in owned_keychain_forms when we are done no
   1136   // longer has a matching database entry.
   1137   std::vector<PasswordForm*> merged_forms;
   1138   internal_keychain_helpers::MergePasswordForms(&owned_keychain_forms,
   1139                                                 &database_forms,
   1140                                                 &merged_forms);
   1141   STLDeleteElements(&merged_forms);
   1142   STLDeleteElements(&database_forms);
   1143 
   1144   return owned_keychain_forms;
   1145 }
   1146 
   1147 void PasswordStoreMac::RemoveDatabaseForms(
   1148     const std::vector<PasswordForm*>& forms) {
   1149   for (std::vector<PasswordForm*>::const_iterator i = forms.begin();
   1150        i != forms.end(); ++i) {
   1151     login_metadata_db_->RemoveLogin(**i);
   1152   }
   1153 }
   1154 
   1155 void PasswordStoreMac::RemoveKeychainForms(
   1156     const std::vector<PasswordForm*>& forms) {
   1157   MacKeychainPasswordFormAdapter owned_keychain_adapter(keychain_.get());
   1158   owned_keychain_adapter.SetFindsOnlyOwnedItems(true);
   1159   for (std::vector<PasswordForm*>::const_iterator i = forms.begin();
   1160        i != forms.end(); ++i) {
   1161     owned_keychain_adapter.RemovePassword(**i);
   1162   }
   1163 }
   1164