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