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