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