password_store_mac.cc revision 9ab5563a3196760eb381d102cbb2bc0f7abc6a50
15821806d5e7f356e8fa4b058a389a808ea183019Torne (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)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/password_manager/password_store_mac.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/password_manager/password_store_mac_internal.h"
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <CoreServices/CoreServices.h>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <set>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector>
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/callback.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/mac/mac_logging.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/mac/mac_util.h"
179ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/stl_util.h"
19868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
20868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/chrome_notification_types.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/password_manager/login_database.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/password_manager/password_store_change.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_service.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "crypto/apple_keychain.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using crypto::AppleKeychain;
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::PasswordForm;
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Utility class to handle the details of constructing and running a keychain
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// search from a set of attributes.
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class KeychainSearch {
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit KeychainSearch(const AppleKeychain& keychain);
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~KeychainSearch();
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Sets up a keycahin search based on an non "null" (NULL for char*,
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The appropriate "Any" entry for other types) arguments.
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // IMPORTANT: Any paramaters passed in *must* remain valid for as long as the
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // KeychainSearch object, since the search uses them by reference.
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Init(const char* server, const UInt32& port,
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            const SecProtocolType& protocol,
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            const SecAuthenticationType& auth_type, const char* security_domain,
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            const char* path, const char* username, OSType creator);
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Fills |items| with all Keychain items that match the Init'd search.
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the search fails for any reason, |items| will be unchanged.
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void FindMatchingItems(std::vector<SecKeychainItemRef>* matches);
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const AppleKeychain* keychain_;
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SecKeychainAttributeList search_attributes_;
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SecKeychainSearchRef search_ref_;
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)KeychainSearch::KeychainSearch(const AppleKeychain& keychain)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : keychain_(&keychain), search_ref_(NULL) {
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  search_attributes_.count = 0;
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  search_attributes_.attr = NULL;
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)KeychainSearch::~KeychainSearch() {
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (search_attributes_.attr) {
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    free(search_attributes_.attr);
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void KeychainSearch::Init(const char* server, const UInt32& port,
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          const SecProtocolType& protocol,
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          const SecAuthenticationType& auth_type,
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          const char* security_domain, const char* path,
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          const char* username, OSType creator) {
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Allocate enough to hold everything we might use.
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const unsigned int kMaxEntryCount = 8;
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  search_attributes_.attr =
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      static_cast<SecKeychainAttribute*>(calloc(kMaxEntryCount,
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                sizeof(SecKeychainAttribute)));
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned int entries = 0;
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We only use search_attributes_ with SearchCreateFromAttributes, which takes
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // a "const SecKeychainAttributeList *", so we trust that they won't try
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to modify the list, and that casting away const-ness is thus safe.
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (server != NULL) {
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_LT(entries, kMaxEntryCount);
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    search_attributes_.attr[entries].tag = kSecServerItemAttr;
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    search_attributes_.attr[entries].length = strlen(server);
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    search_attributes_.attr[entries].data =
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        const_cast<void*>(reinterpret_cast<const void*>(server));
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ++entries;
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (port != kAnyPort) {
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_LE(entries, kMaxEntryCount);
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    search_attributes_.attr[entries].tag = kSecPortItemAttr;
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    search_attributes_.attr[entries].length = sizeof(port);
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    search_attributes_.attr[entries].data =
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        const_cast<void*>(reinterpret_cast<const void*>(&port));
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ++entries;
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (protocol != kSecProtocolTypeAny) {
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_LE(entries, kMaxEntryCount);
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    search_attributes_.attr[entries].tag = kSecProtocolItemAttr;
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    search_attributes_.attr[entries].length = sizeof(protocol);
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    search_attributes_.attr[entries].data =
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        const_cast<void*>(reinterpret_cast<const void*>(&protocol));
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ++entries;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (auth_type != kSecAuthenticationTypeAny) {
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_LE(entries, kMaxEntryCount);
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    search_attributes_.attr[entries].tag = kSecAuthenticationTypeItemAttr;
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    search_attributes_.attr[entries].length = sizeof(auth_type);
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    search_attributes_.attr[entries].data =
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        const_cast<void*>(reinterpret_cast<const void*>(&auth_type));
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ++entries;
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (security_domain != NULL && strlen(security_domain) > 0) {
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_LE(entries, kMaxEntryCount);
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    search_attributes_.attr[entries].tag = kSecSecurityDomainItemAttr;
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    search_attributes_.attr[entries].length = strlen(security_domain);
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    search_attributes_.attr[entries].data =
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        const_cast<void*>(reinterpret_cast<const void*>(security_domain));
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ++entries;
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (path != NULL && strlen(path) > 0 && strcmp(path, "/") != 0) {
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_LE(entries, kMaxEntryCount);
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    search_attributes_.attr[entries].tag = kSecPathItemAttr;
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    search_attributes_.attr[entries].length = strlen(path);
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    search_attributes_.attr[entries].data =
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        const_cast<void*>(reinterpret_cast<const void*>(path));
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ++entries;
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (username != NULL) {
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_LE(entries, kMaxEntryCount);
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    search_attributes_.attr[entries].tag = kSecAccountItemAttr;
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    search_attributes_.attr[entries].length = strlen(username);
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    search_attributes_.attr[entries].data =
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        const_cast<void*>(reinterpret_cast<const void*>(username));
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ++entries;
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (creator != 0) {
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_LE(entries, kMaxEntryCount);
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    search_attributes_.attr[entries].tag = kSecCreatorItemAttr;
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    search_attributes_.attr[entries].length = sizeof(creator);
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    search_attributes_.attr[entries].data =
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        const_cast<void*>(reinterpret_cast<const void*>(&creator));
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ++entries;
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  search_attributes_.count = entries;
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void KeychainSearch::FindMatchingItems(std::vector<SecKeychainItemRef>* items) {
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OSStatus result = keychain_->SearchCreateFromAttributes(
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NULL, kSecInternetPasswordItemClass, &search_attributes_, &search_ref_);
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result != noErr) {
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OSSTATUS_LOG(ERROR, result) << "Keychain lookup failed";
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SecKeychainItemRef keychain_item;
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (keychain_->SearchCopyNext(search_ref_, &keychain_item) == noErr) {
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Consumer is responsible for freeing the items.
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    items->push_back(keychain_item);
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  keychain_->Free(search_ref_);
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  search_ref_ = NULL;
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma mark -
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(stuartmorgan): Convert most of this to private helpers in
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// MacKeychainPasswordFormAdapter once it has sufficient higher-level public
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// methods to provide test coverage.
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace internal_keychain_helpers {
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns a URL built from the given components. To create a URL without a
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// port, pass kAnyPort for the |port| parameter.
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GURL URLFromComponents(bool is_secure, const std::string& host, int port,
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       const std::string& path) {
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GURL::Replacements url_components;
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string scheme(is_secure ? "https" : "http");
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  url_components.SetSchemeStr(scheme);
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  url_components.SetHostStr(host);
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string port_string;  // Must remain in scope until after we do replacing.
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (port != kAnyPort) {
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::ostringstream port_stringstream;
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    port_stringstream << port;
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    port_string = port_stringstream.str();
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_components.SetPortStr(port_string);
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  url_components.SetPathStr(path);
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GURL url("http://dummy.com");  // ReplaceComponents needs a valid URL.
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return url.ReplaceComponents(url_components);
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Converts a Keychain time string to a Time object, returning true if
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// time_string_bytes was parsable. If the return value is false, the value of
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |time| is unchanged.
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TimeFromKeychainTimeString(const char* time_string_bytes,
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                unsigned int byte_length,
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                base::Time* time) {
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(time);
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char* time_string = static_cast<char*>(malloc(byte_length + 1));
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memcpy(time_string, time_string_bytes, byte_length);
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  time_string[byte_length] = '\0';
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::Time::Exploded exploded_time;
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bzero(&exploded_time, sizeof(exploded_time));
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The time string is of the form "yyyyMMddHHmmss'Z", in UTC time.
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int assignments = sscanf(time_string, "%4d%2d%2d%2d%2d%2dZ",
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           &exploded_time.year, &exploded_time.month,
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           &exploded_time.day_of_month, &exploded_time.hour,
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           &exploded_time.minute, &exploded_time.second);
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  free(time_string);
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (assignments == 6) {
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *time = base::Time::FromUTCExploded(exploded_time);
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns the PasswordForm Scheme corresponding to |auth_type|.
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PasswordForm::Scheme SchemeForAuthType(SecAuthenticationType auth_type) {
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (auth_type) {
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case kSecAuthenticationTypeHTMLForm:   return PasswordForm::SCHEME_HTML;
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case kSecAuthenticationTypeHTTPBasic:  return PasswordForm::SCHEME_BASIC;
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case kSecAuthenticationTypeHTTPDigest: return PasswordForm::SCHEME_DIGEST;
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:                               return PasswordForm::SCHEME_OTHER;
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool FillPasswordFormFromKeychainItem(const AppleKeychain& keychain,
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      const SecKeychainItemRef& keychain_item,
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      PasswordForm* form) {
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(form);
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SecKeychainAttributeInfo attrInfo;
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UInt32 tags[] = { kSecAccountItemAttr,
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    kSecServerItemAttr,
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    kSecPortItemAttr,
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    kSecPathItemAttr,
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    kSecProtocolItemAttr,
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    kSecAuthenticationTypeItemAttr,
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    kSecSecurityDomainItemAttr,
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    kSecCreationDateItemAttr,
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    kSecNegativeItemAttr };
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  attrInfo.count = arraysize(tags);
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  attrInfo.tag = tags;
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  attrInfo.format = NULL;
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SecKeychainAttributeList *attrList;
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UInt32 password_length;
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void* password_data;
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OSStatus result = keychain.ItemCopyAttributesAndData(keychain_item, &attrInfo,
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                       NULL, &attrList,
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                       &password_length,
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                       &password_data);
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result != noErr) {
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We don't log errSecAuthFailed because that just means that the user
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // chose not to allow us access to the item.
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (result != errSecAuthFailed) {
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      OSSTATUS_LOG(ERROR, result) << "Keychain data load failed";
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UTF8ToUTF16(static_cast<const char *>(password_data), password_length,
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              &(form->password_value));
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int port = kAnyPort;
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string server;
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string security_domain;
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string path;
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (unsigned int i = 0; i < attrList->count; i++) {
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SecKeychainAttribute attr = attrList->attr[i];
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!attr.data) {
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    switch (attr.tag) {
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case kSecAccountItemAttr:
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        UTF8ToUTF16(static_cast<const char *>(attr.data), attr.length,
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    &(form->username_value));
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case kSecServerItemAttr:
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        server.assign(static_cast<const char *>(attr.data), attr.length);
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case kSecPortItemAttr:
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        port = *(static_cast<UInt32*>(attr.data));
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case kSecPathItemAttr:
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        path.assign(static_cast<const char *>(attr.data), attr.length);
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case kSecProtocolItemAttr:
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      {
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SecProtocolType protocol = *(static_cast<SecProtocolType*>(attr.data));
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // TODO(stuartmorgan): Handle proxy types
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        form->ssl_valid = (protocol == kSecProtocolTypeHTTPS);
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case kSecAuthenticationTypeItemAttr:
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      {
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SecAuthenticationType auth_type =
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            *(static_cast<SecAuthenticationType*>(attr.data));
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        form->scheme = SchemeForAuthType(auth_type);
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case kSecSecurityDomainItemAttr:
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        security_domain.assign(static_cast<const char *>(attr.data),
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               attr.length);
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case kSecCreationDateItemAttr:
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // The only way to get a date out of Keychain is as a string. Really.
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // (The docs claim it's an int, but the header is correct.)
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        TimeFromKeychainTimeString(static_cast<char*>(attr.data), attr.length,
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   &form->date_created);
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case kSecNegativeItemAttr:
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        Boolean negative_item = *(static_cast<Boolean*>(attr.data));
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (negative_item) {
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          form->blacklisted_by_user = true;
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  keychain.ItemFreeAttributesAndData(attrList, password_data);
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // kSecNegativeItemAttr doesn't seem to actually be in widespread use. In
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // practice, other browsers seem to use a "" or " " password (and a special
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // user name) to indicated blacklist entries.
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (form->password_value.empty() || EqualsASCII(form->password_value, " ")) {
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    form->blacklisted_by_user = true;
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  form->origin = URLFromComponents(form->ssl_valid, server, port, path);
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(stuartmorgan): Handle proxies, which need a different signon_realm
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // format.
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  form->signon_realm = form->origin.GetOrigin().spec();
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (form->scheme != PasswordForm::SCHEME_HTML) {
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    form->signon_realm.append(security_domain);
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool FormsMatchForMerge(const PasswordForm& form_a,
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        const PasswordForm& form_b) {
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We never merge blacklist entries between our store and the keychain.
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (form_a.blacklisted_by_user || form_b.blacklisted_by_user) {
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return form_a.scheme == form_b.scheme &&
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         form_a.signon_realm == form_b.signon_realm &&
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         form_a.username_value == form_b.username_value;
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns an the best match for |form| from |keychain_forms|, or NULL if there
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// is no suitable match.
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PasswordForm* BestKeychainFormForForm(
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const PasswordForm& base_form,
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<PasswordForm*>* keychain_forms) {
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PasswordForm* partial_match = NULL;
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<PasswordForm*>::const_iterator i = keychain_forms->begin();
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != keychain_forms->end(); ++i) {
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(stuartmorgan): We should really be scoring path matches and picking
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // the best, rather than just checking exact-or-not (although in practice
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // keychain items with paths probably came from us).
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (FormsMatchForMerge(base_form, *(*i))) {
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (base_form.origin == (*i)->origin) {
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return *i;
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else if (!partial_match) {
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        partial_match = *i;
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return partial_match;
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns entries from |forms| that are blacklist entries, after removing
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// them from |forms|.
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::vector<PasswordForm*> ExtractBlacklistForms(
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<PasswordForm*>* forms) {
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<PasswordForm*> blacklist_forms;
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<PasswordForm*>::iterator i = forms->begin();
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != forms->end();) {
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PasswordForm* form = *i;
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (form->blacklisted_by_user) {
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      blacklist_forms.push_back(form);
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      i = forms->erase(i);
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ++i;
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return blacklist_forms;
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Deletes and removes from v any element that exists in s.
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template <class T>
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DeleteVectorElementsInSet(std::vector<T*>* v, const std::set<T*>& s) {
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (typename std::vector<T*>::iterator i = v->begin(); i != v->end();) {
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    T* element = *i;
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (s.find(element) != s.end()) {
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delete element;
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      i = v->erase(i);
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ++i;
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MergePasswordForms(std::vector<PasswordForm*>* keychain_forms,
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        std::vector<PasswordForm*>* database_forms,
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        std::vector<PasswordForm*>* merged_forms) {
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Pull out the database blacklist items, since they are used as-is rather
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // than being merged with keychain forms.
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<PasswordForm*> database_blacklist_forms =
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ExtractBlacklistForms(database_forms);
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Merge the normal entries.
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::set<PasswordForm*> used_keychain_forms;
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<PasswordForm*>::iterator i = database_forms->begin();
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != database_forms->end();) {
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PasswordForm* db_form = *i;
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PasswordForm* best_match = BestKeychainFormForForm(*db_form,
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                       keychain_forms);
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (best_match) {
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      used_keychain_forms.insert(best_match);
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      db_form->password_value = best_match->password_value;
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      merged_forms->push_back(db_form);
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      i = database_forms->erase(i);
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ++i;
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Add in the blacklist entries from the database.
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  merged_forms->insert(merged_forms->end(),
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       database_blacklist_forms.begin(),
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       database_blacklist_forms.end());
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Clear out all the Keychain entries we used.
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DeleteVectorElementsInSet(keychain_forms, used_keychain_forms);
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::vector<PasswordForm*> GetPasswordsForForms(
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const AppleKeychain& keychain,
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<PasswordForm*>* database_forms) {
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MacKeychainPasswordFormAdapter keychain_adapter(&keychain);
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<PasswordForm*> merged_forms;
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<PasswordForm*>::iterator i = database_forms->begin();
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != database_forms->end();) {
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<PasswordForm*> db_form_container(1, *i);
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<PasswordForm*> keychain_matches =
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        keychain_adapter.PasswordsMergeableWithForm(**i);
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MergePasswordForms(&keychain_matches, &db_form_container, &merged_forms);
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (db_form_container.empty()) {
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      i = database_forms->erase(i);
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ++i;
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    STLDeleteElements(&keychain_matches);
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return merged_forms;
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace internal_keychain_helpers
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma mark -
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MacKeychainPasswordFormAdapter::MacKeychainPasswordFormAdapter(
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const AppleKeychain* keychain)
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : keychain_(keychain), finds_only_owned_(false) {
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::vector<PasswordForm*>
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MacKeychainPasswordFormAdapter::PasswordsFillingForm(
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        const PasswordForm& query_form) {
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<SecKeychainItemRef> keychain_items =
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      MatchingKeychainItems(query_form.signon_realm, query_form.scheme,
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            NULL, NULL);
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ConvertKeychainItemsToForms(&keychain_items);
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::vector<PasswordForm*>
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MacKeychainPasswordFormAdapter::PasswordsMergeableWithForm(
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        const PasswordForm& query_form) {
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string username = UTF16ToUTF8(query_form.username_value);
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<SecKeychainItemRef> keychain_items =
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      MatchingKeychainItems(query_form.signon_realm, query_form.scheme,
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            NULL, username.c_str());
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ConvertKeychainItemsToForms(&keychain_items);
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PasswordForm* MacKeychainPasswordFormAdapter::PasswordExactlyMatchingForm(
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const PasswordForm& query_form) {
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SecKeychainItemRef keychain_item = KeychainItemForForm(query_form);
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (keychain_item) {
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PasswordForm* form = new PasswordForm();
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    internal_keychain_helpers::FillPasswordFormFromKeychainItem(*keychain_,
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                                keychain_item,
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                                form);
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    keychain_->Free(keychain_item);
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return form;
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return NULL;
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool MacKeychainPasswordFormAdapter::HasPasswordsMergeableWithForm(
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const PasswordForm& query_form) {
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string username = UTF16ToUTF8(query_form.username_value);
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<SecKeychainItemRef> matches =
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      MatchingKeychainItems(query_form.signon_realm, query_form.scheme,
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            NULL, username.c_str());
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<SecKeychainItemRef>::iterator i = matches.begin();
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != matches.end(); ++i) {
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    keychain_->Free(*i);
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return !matches.empty();
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::vector<PasswordForm*>
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MacKeychainPasswordFormAdapter::GetAllPasswordFormPasswords() {
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SecAuthenticationType supported_auth_types[] = {
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kSecAuthenticationTypeHTMLForm,
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kSecAuthenticationTypeHTTPBasic,
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kSecAuthenticationTypeHTTPDigest,
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<SecKeychainItemRef> matches;
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (unsigned int i = 0; i < arraysize(supported_auth_types); ++i) {
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    KeychainSearch keychain_search(*keychain_);
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    keychain_search.Init(NULL, 0, kSecProtocolTypeAny, supported_auth_types[i],
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         NULL, NULL, NULL, CreatorCodeForSearch());
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    keychain_search.FindMatchingItems(&matches);
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ConvertKeychainItemsToForms(&matches);
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool MacKeychainPasswordFormAdapter::AddPassword(const PasswordForm& form) {
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We should never be trying to store a blacklist in the keychain.
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!form.blacklisted_by_user);
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string server;
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string security_domain;
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int port;
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool is_secure;
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ExtractSignonRealmComponents(form.signon_realm, &server, &port,
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    &is_secure, &security_domain)) {
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string username = UTF16ToUTF8(form.username_value);
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string password = UTF16ToUTF8(form.password_value);
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string path = form.origin.path();
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SecProtocolType protocol = is_secure ? kSecProtocolTypeHTTPS
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       : kSecProtocolTypeHTTP;
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SecKeychainItemRef new_item = NULL;
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OSStatus result = keychain_->AddInternetPassword(
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NULL, server.size(), server.c_str(),
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      security_domain.size(), security_domain.c_str(),
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      username.size(), username.c_str(),
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      path.size(), path.c_str(),
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      port, protocol, AuthTypeForScheme(form.scheme),
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      password.size(), password.c_str(), &new_item);
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result == noErr) {
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetKeychainItemCreatorCode(new_item,
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               base::mac::CreatorCodeForApplication());
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    keychain_->Free(new_item);
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (result == errSecDuplicateItem) {
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If we collide with an existing item, find and update it instead.
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SecKeychainItemRef existing_item = KeychainItemForForm(form);
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!existing_item) {
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool changed = SetKeychainItemPassword(existing_item, password);
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    keychain_->Free(existing_item);
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return changed;
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result == noErr;
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool MacKeychainPasswordFormAdapter::RemovePassword(const PasswordForm& form) {
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SecKeychainItemRef keychain_item = KeychainItemForForm(form);
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (keychain_item == NULL)
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OSStatus result = keychain_->ItemDelete(keychain_item);
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  keychain_->Free(keychain_item);
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result == noErr;
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MacKeychainPasswordFormAdapter::SetFindsOnlyOwnedItems(
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool finds_only_owned) {
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  finds_only_owned_ = finds_only_owned;
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::vector<PasswordForm*>
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MacKeychainPasswordFormAdapter::ConvertKeychainItemsToForms(
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::vector<SecKeychainItemRef>* items) {
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<PasswordForm*> keychain_forms;
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<SecKeychainItemRef>::const_iterator i = items->begin();
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != items->end(); ++i) {
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PasswordForm* form = new PasswordForm();
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (internal_keychain_helpers::FillPasswordFormFromKeychainItem(*keychain_,
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                                    *i, form)) {
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      keychain_forms.push_back(form);
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    keychain_->Free(*i);
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  items->clear();
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return keychain_forms;
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SecKeychainItemRef MacKeychainPasswordFormAdapter::KeychainItemForForm(
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const PasswordForm& form) {
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We don't store blacklist entries in the keychain, so the answer to "what
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Keychain item goes with this form" is always "nothing" for blacklists.
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (form.blacklisted_by_user) {
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string path = form.origin.path();
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string username = UTF16ToUTF8(form.username_value);
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<SecKeychainItemRef> matches = MatchingKeychainItems(
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      form.signon_realm, form.scheme, path.c_str(), username.c_str());
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (matches.empty()) {
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Free all items after the first, since we won't be returning them.
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<SecKeychainItemRef>::iterator i = matches.begin() + 1;
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != matches.end(); ++i) {
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    keychain_->Free(*i);
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return matches[0];
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::vector<SecKeychainItemRef>
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MacKeychainPasswordFormAdapter::MatchingKeychainItems(
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        const std::string& signon_realm,
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        content::PasswordForm::Scheme scheme,
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        const char* path, const char* username) {
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<SecKeychainItemRef> matches;
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string server;
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string security_domain;
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int port;
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool is_secure;
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ExtractSignonRealmComponents(signon_realm, &server, &port,
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    &is_secure, &security_domain)) {
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(stuartmorgan): Proxies will currently fail here, since their
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // signon_realm is not a URL. We need to detect the proxy case and handle
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // it specially.
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return matches;
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SecProtocolType protocol = is_secure ? kSecProtocolTypeHTTPS
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       : kSecProtocolTypeHTTP;
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SecAuthenticationType auth_type = AuthTypeForScheme(scheme);
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char* auth_domain = (scheme == PasswordForm::SCHEME_HTML) ?
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NULL : security_domain.c_str();
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  KeychainSearch keychain_search(*keychain_);
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  keychain_search.Init(server.c_str(), port, protocol, auth_type,
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       auth_domain, path, username, CreatorCodeForSearch());
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  keychain_search.FindMatchingItems(&matches);
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return matches;
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(stuartmorgan): signon_realm for proxies is not yet supported.
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool MacKeychainPasswordFormAdapter::ExtractSignonRealmComponents(
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& signon_realm, std::string* server, int* port,
6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool* is_secure, std::string* security_domain) {
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The signon_realm will be the Origin portion of a URL for an HTML form,
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // and the same but with the security domain as a path for HTTP auth.
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GURL realm_as_url(signon_realm);
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!realm_as_url.is_valid()) {
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (server)
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *server = realm_as_url.host();
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (is_secure)
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *is_secure = realm_as_url.SchemeIsSecure();
6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (port)
6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *port = realm_as_url.has_port() ? atoi(realm_as_url.port().c_str()) : 0;
6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (security_domain) {
6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Strip the leading '/' off of the path to get the security domain.
6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (realm_as_url.path().length() > 0)
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *security_domain = realm_as_url.path().substr(1);
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else
6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      security_domain->clear();
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns the Keychain SecAuthenticationType type corresponding to |scheme|.
7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SecAuthenticationType MacKeychainPasswordFormAdapter::AuthTypeForScheme(
7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PasswordForm::Scheme scheme) {
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (scheme) {
7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case PasswordForm::SCHEME_HTML:   return kSecAuthenticationTypeHTMLForm;
7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case PasswordForm::SCHEME_BASIC:  return kSecAuthenticationTypeHTTPBasic;
7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case PasswordForm::SCHEME_DIGEST: return kSecAuthenticationTypeHTTPDigest;
7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case PasswordForm::SCHEME_OTHER:  return kSecAuthenticationTypeDefault;
7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NOTREACHED();
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return kSecAuthenticationTypeDefault;
7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool MacKeychainPasswordFormAdapter::SetKeychainItemPassword(
7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const SecKeychainItemRef& keychain_item, const std::string& password) {
7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OSStatus result = keychain_->ItemModifyAttributesAndData(keychain_item, NULL,
7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                           password.size(),
7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                           password.c_str());
7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result == noErr;
7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool MacKeychainPasswordFormAdapter::SetKeychainItemCreatorCode(
7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const SecKeychainItemRef& keychain_item, OSType creator_code) {
7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SecKeychainAttribute attr = { kSecCreatorItemAttr, sizeof(creator_code),
7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                &creator_code };
7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SecKeychainAttributeList attrList = { 1, &attr };
7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OSStatus result = keychain_->ItemModifyAttributesAndData(keychain_item,
7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                           &attrList, 0, NULL);
7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result == noErr;
7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)OSType MacKeychainPasswordFormAdapter::CreatorCodeForSearch() {
7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return finds_only_owned_ ? base::mac::CreatorCodeForApplication() : 0;
7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma mark -
7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PasswordStoreMac::PasswordStoreMac(AppleKeychain* keychain,
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   LoginDatabase* login_db)
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : keychain_(keychain), login_metadata_db_(login_db) {
7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(keychain_.get());
7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(login_metadata_db_.get());
7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PasswordStoreMac::~PasswordStoreMac() {
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (thread_.get()) {
7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thread_->message_loop()->DeleteSoon(FROM_HERE,
7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        notification_service_.release());
7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PasswordStoreMac::Init() {
7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thread_.reset(new base::Thread("Chrome_PasswordStore_Thread"));
7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!thread_->Start()) {
7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thread_.reset(NULL);
7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleTask(base::Bind(&PasswordStoreMac::CreateNotificationService, this));
7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return PasswordStore::Init();
7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PasswordStoreMac::ShutdownOnUIThread() {
7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Mac stores passwords in the system keychain, which can block for an
7672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// arbitrarily long time (most notably, it can block on user confirmation
7682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// from a dialog). Use a dedicated thread to avoid blocking DB thread.
7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PasswordStoreMac::ScheduleTask(const base::Closure& task) {
7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (thread_.get()) {
7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thread_->message_loop()->PostTask(FROM_HERE, task);
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PasswordStoreMac::ReportMetricsImpl() {
7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  login_metadata_db_->ReportMetrics();
7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PasswordStoreMac::AddLoginImpl(const PasswordForm& form) {
7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (AddToKeychainIfNecessary(form)) {
7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (login_metadata_db_->AddLogin(form)) {
7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      PasswordStoreChangeList changes;
7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      changes.push_back(PasswordStoreChange(PasswordStoreChange::ADD, form));
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::NotificationService::current()->Notify(
7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          chrome::NOTIFICATION_LOGINS_CHANGED,
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          content::Source<PasswordStore>(this),
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          content::Details<PasswordStoreChangeList>(&changes));
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PasswordStoreMac::UpdateLoginImpl(const PasswordForm& form) {
7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int update_count = 0;
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!login_metadata_db_->UpdateLogin(form, &update_count))
7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MacKeychainPasswordFormAdapter keychain_adapter(keychain_.get());
8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (update_count == 0 &&
8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !keychain_adapter.HasPasswordsMergeableWithForm(form)) {
8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If the password isn't in either the DB or the keychain, then it must have
8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // been deleted after autofill happened, and should not be re-added.
8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The keychain add will update if there is a collision and add if there
8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // isn't, which is the behavior we want, so there's no separate update call.
8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (AddToKeychainIfNecessary(form)) {
8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PasswordStoreChangeList changes;
8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (update_count == 0) {
8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (login_metadata_db_->AddLogin(form)) {
8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        changes.push_back(PasswordStoreChange(PasswordStoreChange::ADD,
8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              form));
8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      changes.push_back(PasswordStoreChange(PasswordStoreChange::UPDATE,
8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            form));
8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!changes.empty()) {
8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::NotificationService::current()->Notify(
8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          chrome::NOTIFICATION_LOGINS_CHANGED,
8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          content::Source<PasswordStore>(this),
8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          content::Details<PasswordStoreChangeList>(&changes));
8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PasswordStoreMac::RemoveLoginImpl(const PasswordForm& form) {
8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (login_metadata_db_->RemoveLogin(form)) {
8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // See if we own a Keychain item associated with this item. We can do an
8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // exact search rather than messing around with trying to do fuzzy matching
8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // because passwords that we created will always have an exact-match
8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // database entry.
8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // (If a user does lose their profile but not their keychain we'll treat the
8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // entries we find like other imported entries anyway, so it's reasonable to
8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // handle deletes on them the way we would for an imported item.)
8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MacKeychainPasswordFormAdapter owned_keychain_adapter(keychain_.get());
8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    owned_keychain_adapter.SetFindsOnlyOwnedItems(true);
8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PasswordForm* owned_password_form =
8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        owned_keychain_adapter.PasswordExactlyMatchingForm(form);
8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (owned_password_form) {
8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // If we don't have other forms using it (i.e., a form differing only by
8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // the names of the form elements), delete the keychain entry.
8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!DatabaseHasFormMatchingKeychainForm(form)) {
8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        owned_keychain_adapter.RemovePassword(form);
8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PasswordStoreChangeList changes;
8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    changes.push_back(PasswordStoreChange(PasswordStoreChange::REMOVE, form));
8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::NotificationService::current()->Notify(
8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        chrome::NOTIFICATION_LOGINS_CHANGED,
8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        content::Source<PasswordStore>(this),
8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        content::Details<PasswordStoreChangeList>(&changes));
8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PasswordStoreMac::RemoveLoginsCreatedBetweenImpl(
8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const base::Time& delete_begin, const base::Time& delete_end) {
8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<PasswordForm*> forms;
8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (login_metadata_db_->GetLoginsCreatedBetween(delete_begin, delete_end,
8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                  &forms)) {
8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (login_metadata_db_->RemoveLoginsCreatedBetween(delete_begin,
8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                       delete_end)) {
8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // We can't delete from the Keychain by date because we may be sharing
8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // items with database entries that weren't in the delete range. Instead,
8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // we find all the Keychain items we own but aren't using any more and
8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // delete those.
8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::vector<PasswordForm*> orphan_keychain_forms =
8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          GetUnusedKeychainForms();
8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // This is inefficient, since we have to re-look-up each keychain item
8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // one at a time to delete it even though the search step already had a
8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // list of Keychain item references. If this turns out to be noticeably
8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // slow we'll need to rearchitect to allow the search and deletion steps
8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // to share.
8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      RemoveKeychainForms(orphan_keychain_forms);
8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      STLDeleteElements(&orphan_keychain_forms);
8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      PasswordStoreChangeList changes;
8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (std::vector<PasswordForm*>::const_iterator it = forms.begin();
8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           it != forms.end(); ++it) {
8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        changes.push_back(PasswordStoreChange(PasswordStoreChange::REMOVE,
8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              **it));
8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::NotificationService::current()->Notify(
8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          chrome::NOTIFICATION_LOGINS_CHANGED,
8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          content::Source<PasswordStore>(this),
8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          content::Details<PasswordStoreChangeList>(&changes));
8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void PasswordStoreMac::GetLoginsImpl(
8952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const content::PasswordForm& form,
8962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const ConsumerCallbackRunner& callback_runner) {
8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MacKeychainPasswordFormAdapter keychain_adapter(keychain_.get());
8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<PasswordForm*> keychain_forms =
8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      keychain_adapter.PasswordsFillingForm(form);
9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<PasswordForm*> database_forms;
9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  login_metadata_db_->GetLogins(form, &database_forms);
9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<PasswordForm*> matched_forms;
9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  internal_keychain_helpers::MergePasswordForms(&keychain_forms,
9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                &database_forms,
9072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                &matched_forms);
9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Strip any blacklist entries out of the unused Keychain array, then take
9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // all the entries that are left (which we can use as imported passwords).
9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<PasswordForm*> keychain_blacklist_forms =
9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      internal_keychain_helpers::ExtractBlacklistForms(&keychain_forms);
9132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  matched_forms.insert(matched_forms.end(),
9142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                       keychain_forms.begin(),
9152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                       keychain_forms.end());
9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  keychain_forms.clear();
9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STLDeleteElements(&keychain_blacklist_forms);
9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Clean up any orphaned database entries.
9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RemoveDatabaseForms(database_forms);
9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STLDeleteElements(&database_forms);
9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  callback_runner.Run(matched_forms);
9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PasswordStoreMac::GetBlacklistLoginsImpl(GetLoginsRequest* request) {
9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FillBlacklistLogins(&request->value);
9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ForwardLoginsResult(request);
9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PasswordStoreMac::GetAutofillableLoginsImpl(GetLoginsRequest* request) {
9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FillAutofillableLogins(&request->value);
9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ForwardLoginsResult(request);
9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PasswordStoreMac::FillAutofillableLogins(
9375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         std::vector<PasswordForm*>* forms) {
93890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(thread_->message_loop() == base::MessageLoop::current());
9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<PasswordForm*> database_forms;
9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  login_metadata_db_->GetAutofillableLogins(&database_forms);
9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<PasswordForm*> merged_forms =
9445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      internal_keychain_helpers::GetPasswordsForForms(*keychain_,
9455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                      &database_forms);
9465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Clean up any orphaned database entries.
9485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RemoveDatabaseForms(database_forms);
9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STLDeleteElements(&database_forms);
9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  forms->insert(forms->end(), merged_forms.begin(), merged_forms.end());
9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
9535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PasswordStoreMac::FillBlacklistLogins(
9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         std::vector<PasswordForm*>* forms) {
95790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(thread_->message_loop() == base::MessageLoop::current());
9585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return login_metadata_db_->GetBlacklistLogins(forms);
9595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PasswordStoreMac::AddToKeychainIfNecessary(const PasswordForm& form) {
9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (form.blacklisted_by_user) {
9635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
9645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MacKeychainPasswordFormAdapter keychainAdapter(keychain_.get());
9665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return keychainAdapter.AddPassword(form);
9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PasswordStoreMac::DatabaseHasFormMatchingKeychainForm(
9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const content::PasswordForm& form) {
9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool has_match = false;
9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<PasswordForm*> database_forms;
9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  login_metadata_db_->GetLogins(form, &database_forms);
9745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<PasswordForm*>::iterator i = database_forms.begin();
9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != database_forms.end(); ++i) {
9765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (internal_keychain_helpers::FormsMatchForMerge(form, **i) &&
9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        (*i)->origin == form.origin) {
9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      has_match = true;
9795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
9805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STLDeleteElements(&database_forms);
9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return has_match;
9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::vector<PasswordForm*> PasswordStoreMac::GetUnusedKeychainForms() {
9875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<PasswordForm*> database_forms;
9885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  login_metadata_db_->GetAutofillableLogins(&database_forms);
9895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MacKeychainPasswordFormAdapter owned_keychain_adapter(keychain_.get());
9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  owned_keychain_adapter.SetFindsOnlyOwnedItems(true);
9925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<PasswordForm*> owned_keychain_forms =
9935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      owned_keychain_adapter.GetAllPasswordFormPasswords();
9945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Run a merge; anything left in owned_keychain_forms when we are done no
9965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // longer has a matching database entry.
9975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<PasswordForm*> merged_forms;
9985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  internal_keychain_helpers::MergePasswordForms(&owned_keychain_forms,
9995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                &database_forms,
10005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                &merged_forms);
10015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STLDeleteElements(&merged_forms);
10025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STLDeleteElements(&database_forms);
10035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return owned_keychain_forms;
10055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PasswordStoreMac::RemoveDatabaseForms(
10085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<PasswordForm*>& forms) {
10095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<PasswordForm*>::const_iterator i = forms.begin();
10105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != forms.end(); ++i) {
10115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    login_metadata_db_->RemoveLogin(**i);
10125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PasswordStoreMac::RemoveKeychainForms(
10165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<PasswordForm*>& forms) {
10175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MacKeychainPasswordFormAdapter owned_keychain_adapter(keychain_.get());
10185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  owned_keychain_adapter.SetFindsOnlyOwnedItems(true);
10195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<PasswordForm*>::const_iterator i = forms.begin();
10205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != forms.end(); ++i) {
10215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    owned_keychain_adapter.RemovePassword(**i);
10225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PasswordStoreMac::CreateNotificationService() {
10265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  notification_service_.reset(content::NotificationService::Create());
10275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1028