password_store_mac.cc revision c5cede9ae108bb15f6b7a8aea21c7e1fefa2834c
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>
114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include <utility>
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector>
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/callback.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/mac/mac_logging.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/mac/mac_util.h"
189ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/stl_util.h"
20868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
21868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/browser/mac/security_wrappers.h"
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "components/password_manager/core/browser/login_database.h"
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "components/password_manager/core/browser/password_store_change.h"
25effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "content/public/browser/browser_thread.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "crypto/apple_keychain.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)using autofill::PasswordForm;
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using crypto::AppleKeychain;
30c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochusing password_manager::PasswordStoreChange;
31c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochusing password_manager::PasswordStoreChangeList;
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Utility class to handle the details of constructing and running a keychain
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// search from a set of attributes.
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class KeychainSearch {
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit KeychainSearch(const AppleKeychain& keychain);
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~KeychainSearch();
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Sets up a keycahin search based on an non "null" (NULL for char*,
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The appropriate "Any" entry for other types) arguments.
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // IMPORTANT: Any paramaters passed in *must* remain valid for as long as the
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // KeychainSearch object, since the search uses them by reference.
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Init(const char* server, const UInt32& port,
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            const SecProtocolType& protocol,
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            const SecAuthenticationType& auth_type, const char* security_domain,
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            const char* path, const char* username, OSType creator);
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Fills |items| with all Keychain items that match the Init'd search.
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the search fails for any reason, |items| will be unchanged.
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void FindMatchingItems(std::vector<SecKeychainItemRef>* matches);
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const AppleKeychain* keychain_;
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SecKeychainAttributeList search_attributes_;
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SecKeychainSearchRef search_ref_;
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)KeychainSearch::KeychainSearch(const AppleKeychain& keychain)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : keychain_(&keychain), search_ref_(NULL) {
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  search_attributes_.count = 0;
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  search_attributes_.attr = NULL;
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)KeychainSearch::~KeychainSearch() {
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (search_attributes_.attr) {
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    free(search_attributes_.attr);
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void KeychainSearch::Init(const char* server, const UInt32& port,
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          const SecProtocolType& protocol,
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          const SecAuthenticationType& auth_type,
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          const char* security_domain, const char* path,
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          const char* username, OSType creator) {
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Allocate enough to hold everything we might use.
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const unsigned int kMaxEntryCount = 8;
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  search_attributes_.attr =
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      static_cast<SecKeychainAttribute*>(calloc(kMaxEntryCount,
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                sizeof(SecKeychainAttribute)));
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned int entries = 0;
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We only use search_attributes_ with SearchCreateFromAttributes, which takes
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // a "const SecKeychainAttributeList *", so we trust that they won't try
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to modify the list, and that casting away const-ness is thus safe.
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (server != NULL) {
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_LT(entries, kMaxEntryCount);
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    search_attributes_.attr[entries].tag = kSecServerItemAttr;
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    search_attributes_.attr[entries].length = strlen(server);
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    search_attributes_.attr[entries].data =
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        const_cast<void*>(reinterpret_cast<const void*>(server));
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ++entries;
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (port != kAnyPort) {
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_LE(entries, kMaxEntryCount);
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    search_attributes_.attr[entries].tag = kSecPortItemAttr;
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    search_attributes_.attr[entries].length = sizeof(port);
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    search_attributes_.attr[entries].data =
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        const_cast<void*>(reinterpret_cast<const void*>(&port));
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ++entries;
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (protocol != kSecProtocolTypeAny) {
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_LE(entries, kMaxEntryCount);
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    search_attributes_.attr[entries].tag = kSecProtocolItemAttr;
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    search_attributes_.attr[entries].length = sizeof(protocol);
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    search_attributes_.attr[entries].data =
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        const_cast<void*>(reinterpret_cast<const void*>(&protocol));
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ++entries;
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (auth_type != kSecAuthenticationTypeAny) {
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_LE(entries, kMaxEntryCount);
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    search_attributes_.attr[entries].tag = kSecAuthenticationTypeItemAttr;
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    search_attributes_.attr[entries].length = sizeof(auth_type);
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    search_attributes_.attr[entries].data =
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        const_cast<void*>(reinterpret_cast<const void*>(&auth_type));
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ++entries;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (security_domain != NULL && strlen(security_domain) > 0) {
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_LE(entries, kMaxEntryCount);
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    search_attributes_.attr[entries].tag = kSecSecurityDomainItemAttr;
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    search_attributes_.attr[entries].length = strlen(security_domain);
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    search_attributes_.attr[entries].data =
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        const_cast<void*>(reinterpret_cast<const void*>(security_domain));
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ++entries;
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (path != NULL && strlen(path) > 0 && strcmp(path, "/") != 0) {
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_LE(entries, kMaxEntryCount);
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    search_attributes_.attr[entries].tag = kSecPathItemAttr;
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    search_attributes_.attr[entries].length = strlen(path);
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    search_attributes_.attr[entries].data =
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        const_cast<void*>(reinterpret_cast<const void*>(path));
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ++entries;
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (username != NULL) {
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_LE(entries, kMaxEntryCount);
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    search_attributes_.attr[entries].tag = kSecAccountItemAttr;
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    search_attributes_.attr[entries].length = strlen(username);
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    search_attributes_.attr[entries].data =
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        const_cast<void*>(reinterpret_cast<const void*>(username));
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ++entries;
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (creator != 0) {
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_LE(entries, kMaxEntryCount);
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    search_attributes_.attr[entries].tag = kSecCreatorItemAttr;
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    search_attributes_.attr[entries].length = sizeof(creator);
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    search_attributes_.attr[entries].data =
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        const_cast<void*>(reinterpret_cast<const void*>(&creator));
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ++entries;
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  search_attributes_.count = entries;
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void KeychainSearch::FindMatchingItems(std::vector<SecKeychainItemRef>* items) {
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OSStatus result = keychain_->SearchCreateFromAttributes(
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NULL, kSecInternetPasswordItemClass, &search_attributes_, &search_ref_);
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result != noErr) {
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OSSTATUS_LOG(ERROR, result) << "Keychain lookup failed";
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SecKeychainItemRef keychain_item;
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (keychain_->SearchCopyNext(search_ref_, &keychain_item) == noErr) {
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Consumer is responsible for freeing the items.
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    items->push_back(keychain_item);
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  keychain_->Free(search_ref_);
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  search_ref_ = NULL;
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma mark -
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(stuartmorgan): Convert most of this to private helpers in
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// MacKeychainPasswordFormAdapter once it has sufficient higher-level public
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// methods to provide test coverage.
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace internal_keychain_helpers {
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns a URL built from the given components. To create a URL without a
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// port, pass kAnyPort for the |port| parameter.
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GURL URLFromComponents(bool is_secure, const std::string& host, int port,
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       const std::string& path) {
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GURL::Replacements url_components;
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string scheme(is_secure ? "https" : "http");
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  url_components.SetSchemeStr(scheme);
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  url_components.SetHostStr(host);
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string port_string;  // Must remain in scope until after we do replacing.
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (port != kAnyPort) {
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::ostringstream port_stringstream;
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    port_stringstream << port;
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    port_string = port_stringstream.str();
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_components.SetPortStr(port_string);
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  url_components.SetPathStr(path);
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GURL url("http://dummy.com");  // ReplaceComponents needs a valid URL.
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return url.ReplaceComponents(url_components);
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Converts a Keychain time string to a Time object, returning true if
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// time_string_bytes was parsable. If the return value is false, the value of
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |time| is unchanged.
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TimeFromKeychainTimeString(const char* time_string_bytes,
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                unsigned int byte_length,
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                base::Time* time) {
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(time);
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char* time_string = static_cast<char*>(malloc(byte_length + 1));
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memcpy(time_string, time_string_bytes, byte_length);
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  time_string[byte_length] = '\0';
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::Time::Exploded exploded_time;
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bzero(&exploded_time, sizeof(exploded_time));
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The time string is of the form "yyyyMMddHHmmss'Z", in UTC time.
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int assignments = sscanf(time_string, "%4d%2d%2d%2d%2d%2dZ",
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           &exploded_time.year, &exploded_time.month,
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           &exploded_time.day_of_month, &exploded_time.hour,
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           &exploded_time.minute, &exploded_time.second);
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  free(time_string);
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (assignments == 6) {
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *time = base::Time::FromUTCExploded(exploded_time);
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns the PasswordForm Scheme corresponding to |auth_type|.
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PasswordForm::Scheme SchemeForAuthType(SecAuthenticationType auth_type) {
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (auth_type) {
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case kSecAuthenticationTypeHTMLForm:   return PasswordForm::SCHEME_HTML;
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case kSecAuthenticationTypeHTTPBasic:  return PasswordForm::SCHEME_BASIC;
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case kSecAuthenticationTypeHTTPDigest: return PasswordForm::SCHEME_DIGEST;
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:                               return PasswordForm::SCHEME_OTHER;
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool FillPasswordFormFromKeychainItem(const AppleKeychain& keychain,
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      const SecKeychainItemRef& keychain_item,
2394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                      PasswordForm* form,
2404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                      bool extract_password_data) {
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(form);
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SecKeychainAttributeInfo attrInfo;
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UInt32 tags[] = { kSecAccountItemAttr,
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    kSecServerItemAttr,
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    kSecPortItemAttr,
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    kSecPathItemAttr,
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    kSecProtocolItemAttr,
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    kSecAuthenticationTypeItemAttr,
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    kSecSecurityDomainItemAttr,
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    kSecCreationDateItemAttr,
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    kSecNegativeItemAttr };
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  attrInfo.count = arraysize(tags);
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  attrInfo.tag = tags;
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  attrInfo.format = NULL;
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SecKeychainAttributeList *attrList;
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UInt32 password_length;
2594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // If |extract_password_data| is false, do not pass in a reference to
2614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // |password_data|. ItemCopyAttributesAndData will then extract only the
2624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // attributes of |keychain_item| (doesn't require OS authorization), and not
2634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // attempt to extract its password data (requires OS authorization).
2644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  void* password_data = NULL;
2654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  void** password_data_ref = extract_password_data ? &password_data : NULL;
2664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OSStatus result = keychain.ItemCopyAttributesAndData(keychain_item, &attrInfo,
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                       NULL, &attrList,
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                       &password_length,
2704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                                       password_data_ref);
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result != noErr) {
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We don't log errSecAuthFailed because that just means that the user
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // chose not to allow us access to the item.
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (result != errSecAuthFailed) {
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      OSSTATUS_LOG(ERROR, result) << "Keychain data load failed";
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (extract_password_data) {
2825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::UTF8ToUTF16(static_cast<const char *>(password_data), password_length,
2835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                      &(form->password_value));
2844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int port = kAnyPort;
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string server;
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string security_domain;
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string path;
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (unsigned int i = 0; i < attrList->count; i++) {
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SecKeychainAttribute attr = attrList->attr[i];
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!attr.data) {
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    switch (attr.tag) {
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case kSecAccountItemAttr:
2975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        base::UTF8ToUTF16(static_cast<const char *>(attr.data), attr.length,
2985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                          &(form->username_value));
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case kSecServerItemAttr:
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        server.assign(static_cast<const char *>(attr.data), attr.length);
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case kSecPortItemAttr:
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        port = *(static_cast<UInt32*>(attr.data));
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case kSecPathItemAttr:
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        path.assign(static_cast<const char *>(attr.data), attr.length);
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case kSecProtocolItemAttr:
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      {
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SecProtocolType protocol = *(static_cast<SecProtocolType*>(attr.data));
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // TODO(stuartmorgan): Handle proxy types
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        form->ssl_valid = (protocol == kSecProtocolTypeHTTPS);
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case kSecAuthenticationTypeItemAttr:
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      {
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SecAuthenticationType auth_type =
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            *(static_cast<SecAuthenticationType*>(attr.data));
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        form->scheme = SchemeForAuthType(auth_type);
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case kSecSecurityDomainItemAttr:
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        security_domain.assign(static_cast<const char *>(attr.data),
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               attr.length);
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case kSecCreationDateItemAttr:
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // The only way to get a date out of Keychain is as a string. Really.
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // (The docs claim it's an int, but the header is correct.)
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        TimeFromKeychainTimeString(static_cast<char*>(attr.data), attr.length,
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   &form->date_created);
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case kSecNegativeItemAttr:
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        Boolean negative_item = *(static_cast<Boolean*>(attr.data));
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (negative_item) {
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          form->blacklisted_by_user = true;
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  keychain.ItemFreeAttributesAndData(attrList, password_data);
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // kSecNegativeItemAttr doesn't seem to actually be in widespread use. In
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // practice, other browsers seem to use a "" or " " password (and a special
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // user name) to indicated blacklist entries.
3464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (extract_password_data && (form->password_value.empty() ||
3474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                EqualsASCII(form->password_value, " "))) {
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    form->blacklisted_by_user = true;
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  form->origin = URLFromComponents(form->ssl_valid, server, port, path);
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(stuartmorgan): Handle proxies, which need a different signon_realm
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // format.
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  form->signon_realm = form->origin.GetOrigin().spec();
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (form->scheme != PasswordForm::SCHEME_HTML) {
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    form->signon_realm.append(security_domain);
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool FormsMatchForMerge(const PasswordForm& form_a,
3625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        const PasswordForm& form_b,
3635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        FormMatchStrictness strictness) {
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We never merge blacklist entries between our store and the keychain.
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (form_a.blacklisted_by_user || form_b.blacklisted_by_user) {
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool equal_realm = form_a.signon_realm == form_b.signon_realm;
3695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (strictness == FUZZY_FORM_MATCH) {
3705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    equal_realm |= (!form_a.original_signon_realm.empty()) &&
3715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                   form_a.original_signon_realm == form_b.signon_realm;
3725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return form_a.scheme == form_b.scheme && equal_realm &&
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         form_a.username_value == form_b.username_value;
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Returns an the best match for |base_form| from |keychain_forms|, or NULL if
3785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// there is no suitable match.
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PasswordForm* BestKeychainFormForForm(
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const PasswordForm& base_form,
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<PasswordForm*>* keychain_forms) {
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PasswordForm* partial_match = NULL;
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<PasswordForm*>::const_iterator i = keychain_forms->begin();
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != keychain_forms->end(); ++i) {
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(stuartmorgan): We should really be scoring path matches and picking
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // the best, rather than just checking exact-or-not (although in practice
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // keychain items with paths probably came from us).
3885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (FormsMatchForMerge(base_form, *(*i), FUZZY_FORM_MATCH)) {
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (base_form.origin == (*i)->origin) {
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return *i;
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else if (!partial_match) {
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        partial_match = *i;
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return partial_match;
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns entries from |forms| that are blacklist entries, after removing
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// them from |forms|.
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::vector<PasswordForm*> ExtractBlacklistForms(
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<PasswordForm*>* forms) {
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<PasswordForm*> blacklist_forms;
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<PasswordForm*>::iterator i = forms->begin();
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != forms->end();) {
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PasswordForm* form = *i;
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (form->blacklisted_by_user) {
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      blacklist_forms.push_back(form);
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      i = forms->erase(i);
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ++i;
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return blacklist_forms;
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Deletes and removes from v any element that exists in s.
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template <class T>
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DeleteVectorElementsInSet(std::vector<T*>* v, const std::set<T*>& s) {
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (typename std::vector<T*>::iterator i = v->begin(); i != v->end();) {
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    T* element = *i;
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (s.find(element) != s.end()) {
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delete element;
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      i = v->erase(i);
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ++i;
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MergePasswordForms(std::vector<PasswordForm*>* keychain_forms,
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        std::vector<PasswordForm*>* database_forms,
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        std::vector<PasswordForm*>* merged_forms) {
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Pull out the database blacklist items, since they are used as-is rather
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // than being merged with keychain forms.
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<PasswordForm*> database_blacklist_forms =
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ExtractBlacklistForms(database_forms);
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Merge the normal entries.
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::set<PasswordForm*> used_keychain_forms;
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<PasswordForm*>::iterator i = database_forms->begin();
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != database_forms->end();) {
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PasswordForm* db_form = *i;
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PasswordForm* best_match = BestKeychainFormForForm(*db_form,
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                       keychain_forms);
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (best_match) {
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      used_keychain_forms.insert(best_match);
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      db_form->password_value = best_match->password_value;
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      merged_forms->push_back(db_form);
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      i = database_forms->erase(i);
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ++i;
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Add in the blacklist entries from the database.
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  merged_forms->insert(merged_forms->end(),
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       database_blacklist_forms.begin(),
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       database_blacklist_forms.end());
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Clear out all the Keychain entries we used.
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DeleteVectorElementsInSet(keychain_forms, used_keychain_forms);
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)std::vector<ItemFormPair> ExtractAllKeychainItemAttributesIntoPasswordForms(
4664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    std::vector<SecKeychainItemRef>* keychain_items,
4674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const AppleKeychain& keychain) {
4684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DCHECK(keychain_items);
4694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  MacKeychainPasswordFormAdapter keychain_adapter(&keychain);
4704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  *keychain_items = keychain_adapter.GetAllPasswordFormKeychainItems();
4714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  std::vector<ItemFormPair> item_form_pairs;
4724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  for (std::vector<SecKeychainItemRef>::iterator i = keychain_items->begin();
4734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)       i != keychain_items->end(); ++i) {
4744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    PasswordForm* form_without_password = new PasswordForm();
4754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    internal_keychain_helpers::FillPasswordFormFromKeychainItem(
4764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        keychain,
4774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        *i,
4784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        form_without_password,
4794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        false);  // Load password attributes, but not password data.
4804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    item_form_pairs.push_back(std::make_pair(&(*i), form_without_password));
4814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
4824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return item_form_pairs;
4834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
4844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::vector<PasswordForm*> GetPasswordsForForms(
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const AppleKeychain& keychain,
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<PasswordForm*>* database_forms) {
4884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // First load the attributes of all items in the keychain without loading
4894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // their password data, and then match items in |database_forms| against them.
4904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // This avoids individually searching through the keychain for passwords
4914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // matching each form in |database_forms|, and results in a significant
4924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // performance gain, replacing O(N) keychain search operations with a single
4934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // operation that loads all keychain items, and then selective reads of only
4944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // the relevant passwords. See crbug.com/263685.
4954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  std::vector<SecKeychainItemRef> keychain_items;
4964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  std::vector<ItemFormPair> item_form_pairs =
4974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      ExtractAllKeychainItemAttributesIntoPasswordForms(&keychain_items,
4984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                                        keychain);
4994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
5004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Next, compare the attributes of the PasswordForms in |database_forms|
5014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // against those in |item_form_pairs|, and extract password data for each
5024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // matching PasswordForm using its corresponding SecKeychainItemRef.
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<PasswordForm*> merged_forms;
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<PasswordForm*>::iterator i = database_forms->begin();
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != database_forms->end();) {
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<PasswordForm*> db_form_container(1, *i);
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<PasswordForm*> keychain_matches =
5084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        ExtractPasswordsMergeableWithForm(keychain, item_form_pairs, **i);
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MergePasswordForms(&keychain_matches, &db_form_container, &merged_forms);
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (db_form_container.empty()) {
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      i = database_forms->erase(i);
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ++i;
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    STLDeleteElements(&keychain_matches);
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
5184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Clean up temporary PasswordForms and SecKeychainItemRefs.
5194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  STLDeleteContainerPairSecondPointers(item_form_pairs.begin(),
5204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                       item_form_pairs.end());
5214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  for (std::vector<SecKeychainItemRef>::iterator i = keychain_items.begin();
5224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)       i != keychain_items.end(); ++i) {
5234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    keychain.Free(*i);
5244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return merged_forms;
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// TODO(stuartmorgan): signon_realm for proxies is not yet supported.
5294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool ExtractSignonRealmComponents(
5304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const std::string& signon_realm, std::string* server, int* port,
5314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    bool* is_secure, std::string* security_domain) {
5324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // The signon_realm will be the Origin portion of a URL for an HTML form,
5334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // and the same but with the security domain as a path for HTTP auth.
5344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  GURL realm_as_url(signon_realm);
5354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!realm_as_url.is_valid()) {
5364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return false;
537d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
5384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
5394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (server)
5404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    *server = realm_as_url.host();
5414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (is_secure)
5424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    *is_secure = realm_as_url.SchemeIsSecure();
5434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (port)
5444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    *port = realm_as_url.has_port() ? atoi(realm_as_url.port().c_str()) : 0;
5454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (security_domain) {
5464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // Strip the leading '/' off of the path to get the security domain.
5474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if (realm_as_url.path().length() > 0)
5484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      *security_domain = realm_as_url.path().substr(1);
5494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    else
5504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      security_domain->clear();
5514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
5524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return true;
5534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
5544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
5554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool FormIsValidAndMatchesOtherForm(const PasswordForm& query_form,
5564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                    const PasswordForm& other_form) {
5574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  std::string server;
5584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  std::string security_domain;
5594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  int port;
5604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  bool is_secure;
5614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!ExtractSignonRealmComponents(query_form.signon_realm, &server, &port,
5624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                    &is_secure, &security_domain)) {
5634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return false;
5644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
5655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return internal_keychain_helpers::FormsMatchForMerge(
5665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      query_form, other_form, STRICT_FORM_MATCH);
5674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
5684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
5694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)std::vector<PasswordForm*> ExtractPasswordsMergeableWithForm(
5704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const AppleKeychain& keychain,
5714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const std::vector<ItemFormPair>& item_form_pairs,
5724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const PasswordForm& query_form) {
5734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  std::vector<PasswordForm*> matches;
5744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  for (std::vector<ItemFormPair>::const_iterator i = item_form_pairs.begin();
5754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)       i != item_form_pairs.end(); ++i) {
5764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if (FormIsValidAndMatchesOtherForm(query_form, *(i->second))) {
5774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      // Create a new object, since the caller is responsible for deleting the
5784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      // returned forms.
5794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      scoped_ptr<PasswordForm> form_with_password(new PasswordForm());
5804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      internal_keychain_helpers::FillPasswordFormFromKeychainItem(
5814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          keychain,
5824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          *(i->first),
5834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          form_with_password.get(),
5844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          true);  // Load password attributes and data.
5854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      // Do not include blacklisted items found in the keychain.
5864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      if (!form_with_password->blacklisted_by_user)
5874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        matches.push_back(form_with_password.release());
5884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    }
5894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
5904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return matches;
5914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
592d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace internal_keychain_helpers
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma mark -
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MacKeychainPasswordFormAdapter::MacKeychainPasswordFormAdapter(
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const AppleKeychain* keychain)
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : keychain_(keychain), finds_only_owned_(false) {
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)std::vector<PasswordForm*> MacKeychainPasswordFormAdapter::PasswordsFillingForm(
6035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& signon_realm,
6045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    PasswordForm::Scheme scheme) {
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<SecKeychainItemRef> keychain_items =
6065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      MatchingKeychainItems(signon_realm, scheme, NULL, NULL);
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ConvertKeychainItemsToForms(&keychain_items);
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PasswordForm* MacKeychainPasswordFormAdapter::PasswordExactlyMatchingForm(
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const PasswordForm& query_form) {
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SecKeychainItemRef keychain_item = KeychainItemForForm(query_form);
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (keychain_item) {
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PasswordForm* form = new PasswordForm();
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    internal_keychain_helpers::FillPasswordFormFromKeychainItem(*keychain_,
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                                keychain_item,
6184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                                                form,
6194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                                                true);
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    keychain_->Free(keychain_item);
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return form;
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return NULL;
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool MacKeychainPasswordFormAdapter::HasPasswordsMergeableWithForm(
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const PasswordForm& query_form) {
6285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string username = base::UTF16ToUTF8(query_form.username_value);
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<SecKeychainItemRef> matches =
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      MatchingKeychainItems(query_form.signon_realm, query_form.scheme,
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            NULL, username.c_str());
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<SecKeychainItemRef>::iterator i = matches.begin();
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != matches.end(); ++i) {
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    keychain_->Free(*i);
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return !matches.empty();
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)std::vector<SecKeychainItemRef>
6414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    MacKeychainPasswordFormAdapter::GetAllPasswordFormKeychainItems() {
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SecAuthenticationType supported_auth_types[] = {
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kSecAuthenticationTypeHTMLForm,
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kSecAuthenticationTypeHTTPBasic,
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kSecAuthenticationTypeHTTPDigest,
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<SecKeychainItemRef> matches;
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (unsigned int i = 0; i < arraysize(supported_auth_types); ++i) {
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    KeychainSearch keychain_search(*keychain_);
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    keychain_search.Init(NULL, 0, kSecProtocolTypeAny, supported_auth_types[i],
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         NULL, NULL, NULL, CreatorCodeForSearch());
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    keychain_search.FindMatchingItems(&matches);
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return matches;
6564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)std::vector<PasswordForm*>
6594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    MacKeychainPasswordFormAdapter::GetAllPasswordFormPasswords() {
6604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  std::vector<SecKeychainItemRef> items = GetAllPasswordFormKeychainItems();
6614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return ConvertKeychainItemsToForms(&items);
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool MacKeychainPasswordFormAdapter::AddPassword(const PasswordForm& form) {
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We should never be trying to store a blacklist in the keychain.
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!form.blacklisted_by_user);
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string server;
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string security_domain;
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int port;
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool is_secure;
6724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!internal_keychain_helpers::ExtractSignonRealmComponents(
6734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)           form.signon_realm, &server, &port, &is_secure, &security_domain)) {
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string username = base::UTF16ToUTF8(form.username_value);
6775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string password = base::UTF16ToUTF8(form.password_value);
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string path = form.origin.path();
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SecProtocolType protocol = is_secure ? kSecProtocolTypeHTTPS
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       : kSecProtocolTypeHTTP;
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SecKeychainItemRef new_item = NULL;
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OSStatus result = keychain_->AddInternetPassword(
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NULL, server.size(), server.c_str(),
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      security_domain.size(), security_domain.c_str(),
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      username.size(), username.c_str(),
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      path.size(), path.c_str(),
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      port, protocol, AuthTypeForScheme(form.scheme),
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      password.size(), password.c_str(), &new_item);
6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result == noErr) {
6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetKeychainItemCreatorCode(new_item,
6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               base::mac::CreatorCodeForApplication());
6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    keychain_->Free(new_item);
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (result == errSecDuplicateItem) {
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If we collide with an existing item, find and update it instead.
6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SecKeychainItemRef existing_item = KeychainItemForForm(form);
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!existing_item) {
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool changed = SetKeychainItemPassword(existing_item, password);
7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    keychain_->Free(existing_item);
7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return changed;
7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result == noErr;
7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool MacKeychainPasswordFormAdapter::RemovePassword(const PasswordForm& form) {
7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SecKeychainItemRef keychain_item = KeychainItemForForm(form);
7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (keychain_item == NULL)
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OSStatus result = keychain_->ItemDelete(keychain_item);
7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  keychain_->Free(keychain_item);
7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result == noErr;
7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MacKeychainPasswordFormAdapter::SetFindsOnlyOwnedItems(
7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool finds_only_owned) {
7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  finds_only_owned_ = finds_only_owned;
7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::vector<PasswordForm*>
7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MacKeychainPasswordFormAdapter::ConvertKeychainItemsToForms(
7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::vector<SecKeychainItemRef>* items) {
7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<PasswordForm*> keychain_forms;
7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<SecKeychainItemRef>::const_iterator i = items->begin();
7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != items->end(); ++i) {
7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PasswordForm* form = new PasswordForm();
7294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if (internal_keychain_helpers::FillPasswordFormFromKeychainItem(
7304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)            *keychain_, *i, form, true)) {
7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      keychain_forms.push_back(form);
7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    keychain_->Free(*i);
7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  items->clear();
7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return keychain_forms;
7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SecKeychainItemRef MacKeychainPasswordFormAdapter::KeychainItemForForm(
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const PasswordForm& form) {
7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We don't store blacklist entries in the keychain, so the answer to "what
7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Keychain item goes with this form" is always "nothing" for blacklists.
7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (form.blacklisted_by_user) {
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string path = form.origin.path();
7485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string username = base::UTF16ToUTF8(form.username_value);
7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<SecKeychainItemRef> matches = MatchingKeychainItems(
7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      form.signon_realm, form.scheme, path.c_str(), username.c_str());
7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (matches.empty()) {
7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Free all items after the first, since we won't be returning them.
7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<SecKeychainItemRef>::iterator i = matches.begin() + 1;
7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != matches.end(); ++i) {
7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    keychain_->Free(*i);
7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return matches[0];
7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::vector<SecKeychainItemRef>
7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MacKeychainPasswordFormAdapter::MatchingKeychainItems(
7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        const std::string& signon_realm,
76658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        autofill::PasswordForm::Scheme scheme,
7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        const char* path, const char* username) {
7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<SecKeychainItemRef> matches;
7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string server;
7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string security_domain;
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int port;
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool is_secure;
7744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!internal_keychain_helpers::ExtractSignonRealmComponents(
7754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)           signon_realm, &server, &port, &is_secure, &security_domain)) {
7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(stuartmorgan): Proxies will currently fail here, since their
7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // signon_realm is not a URL. We need to detect the proxy case and handle
7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // it specially.
7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return matches;
7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SecProtocolType protocol = is_secure ? kSecProtocolTypeHTTPS
7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       : kSecProtocolTypeHTTP;
7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SecAuthenticationType auth_type = AuthTypeForScheme(scheme);
7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char* auth_domain = (scheme == PasswordForm::SCHEME_HTML) ?
7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NULL : security_domain.c_str();
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  KeychainSearch keychain_search(*keychain_);
7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  keychain_search.Init(server.c_str(), port, protocol, auth_type,
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       auth_domain, path, username, CreatorCodeForSearch());
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  keychain_search.FindMatchingItems(&matches);
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return matches;
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns the Keychain SecAuthenticationType type corresponding to |scheme|.
7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SecAuthenticationType MacKeychainPasswordFormAdapter::AuthTypeForScheme(
7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PasswordForm::Scheme scheme) {
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (scheme) {
7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case PasswordForm::SCHEME_HTML:   return kSecAuthenticationTypeHTMLForm;
7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case PasswordForm::SCHEME_BASIC:  return kSecAuthenticationTypeHTTPBasic;
7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case PasswordForm::SCHEME_DIGEST: return kSecAuthenticationTypeHTTPDigest;
8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case PasswordForm::SCHEME_OTHER:  return kSecAuthenticationTypeDefault;
8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NOTREACHED();
8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return kSecAuthenticationTypeDefault;
8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool MacKeychainPasswordFormAdapter::SetKeychainItemPassword(
8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const SecKeychainItemRef& keychain_item, const std::string& password) {
8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OSStatus result = keychain_->ItemModifyAttributesAndData(keychain_item, NULL,
8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                           password.size(),
8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                           password.c_str());
8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result == noErr;
8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool MacKeychainPasswordFormAdapter::SetKeychainItemCreatorCode(
8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const SecKeychainItemRef& keychain_item, OSType creator_code) {
8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SecKeychainAttribute attr = { kSecCreatorItemAttr, sizeof(creator_code),
8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                &creator_code };
8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SecKeychainAttributeList attrList = { 1, &attr };
8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OSStatus result = keychain_->ItemModifyAttributesAndData(keychain_item,
8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                           &attrList, 0, NULL);
8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result == noErr;
8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)OSType MacKeychainPasswordFormAdapter::CreatorCodeForSearch() {
8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return finds_only_owned_ ? base::mac::CreatorCodeForApplication() : 0;
8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma mark -
8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)PasswordStoreMac::PasswordStoreMac(
8315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner,
8325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_refptr<base::SingleThreadTaskRunner> db_thread_runner,
8335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    AppleKeychain* keychain,
834c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    password_manager::LoginDatabase* login_db)
835c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    : password_manager::PasswordStore(main_thread_runner, db_thread_runner),
8365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      keychain_(keychain),
8375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      login_metadata_db_(login_db) {
8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(keychain_.get());
8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(login_metadata_db_.get());
8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)PasswordStoreMac::~PasswordStoreMac() {}
8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
844a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool PasswordStoreMac::Init(
845a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const syncer::SyncableService::StartSyncFlare& flare) {
846effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
8474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  thread_.reset(new base::Thread("Chrome_PasswordStore_Thread"));
8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!thread_->Start()) {
8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    thread_.reset(NULL);
8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
853c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  return password_manager::PasswordStore::Init(flare);
8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
856effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid PasswordStoreMac::Shutdown() {
857effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
858c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  password_manager::PasswordStore::Shutdown();
859effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  thread_->Stop();
860effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
861effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
8622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Mac stores passwords in the system keychain, which can block for an
8632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// arbitrarily long time (most notably, it can block on user confirmation
8645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// from a dialog). Run tasks on a dedicated thread to avoid blocking the DB
8655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// thread.
8665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)scoped_refptr<base::SingleThreadTaskRunner>
8675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)PasswordStoreMac::GetBackgroundTaskRunner() {
8685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return (thread_.get()) ? thread_->message_loop_proxy() : NULL;
8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PasswordStoreMac::ReportMetricsImpl() {
8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  login_metadata_db_->ReportMetrics();
8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)PasswordStoreChangeList PasswordStoreMac::AddLoginImpl(
8765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const PasswordForm& form) {
8775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  PasswordStoreChangeList changes;
8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (AddToKeychainIfNecessary(form)) {
8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (login_metadata_db_->AddLogin(form)) {
8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      changes.push_back(PasswordStoreChange(PasswordStoreChange::ADD, form));
8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return changes;
8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)PasswordStoreChangeList PasswordStoreMac::UpdateLoginImpl(
8875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const PasswordForm& form) {
8885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  PasswordStoreChangeList changes;
8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int update_count = 0;
8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!login_metadata_db_->UpdateLogin(form, &update_count))
8915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return changes;
8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MacKeychainPasswordFormAdapter keychain_adapter(keychain_.get());
8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (update_count == 0 &&
8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !keychain_adapter.HasPasswordsMergeableWithForm(form)) {
8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If the password isn't in either the DB or the keychain, then it must have
8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // been deleted after autofill happened, and should not be re-added.
8985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return changes;
8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The keychain add will update if there is a collision and add if there
9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // isn't, which is the behavior we want, so there's no separate update call.
9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (AddToKeychainIfNecessary(form)) {
9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (update_count == 0) {
9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (login_metadata_db_->AddLogin(form)) {
9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        changes.push_back(PasswordStoreChange(PasswordStoreChange::ADD,
9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              form));
9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      changes.push_back(PasswordStoreChange(PasswordStoreChange::UPDATE,
9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            form));
9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return changes;
9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)PasswordStoreChangeList PasswordStoreMac::RemoveLoginImpl(
9185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const PasswordForm& form) {
9195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  PasswordStoreChangeList changes;
9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (login_metadata_db_->RemoveLogin(form)) {
9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // See if we own a Keychain item associated with this item. We can do an
9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // exact search rather than messing around with trying to do fuzzy matching
9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // because passwords that we created will always have an exact-match
9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // database entry.
9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // (If a user does lose their profile but not their keychain we'll treat the
9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // entries we find like other imported entries anyway, so it's reasonable to
9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // handle deletes on them the way we would for an imported item.)
9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MacKeychainPasswordFormAdapter owned_keychain_adapter(keychain_.get());
9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    owned_keychain_adapter.SetFindsOnlyOwnedItems(true);
9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PasswordForm* owned_password_form =
9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        owned_keychain_adapter.PasswordExactlyMatchingForm(form);
9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (owned_password_form) {
9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // If we don't have other forms using it (i.e., a form differing only by
9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // the names of the form elements), delete the keychain entry.
9355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!DatabaseHasFormMatchingKeychainForm(form)) {
9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        owned_keychain_adapter.RemovePassword(form);
9375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
9385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    changes.push_back(PasswordStoreChange(PasswordStoreChange::REMOVE, form));
9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return changes;
9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)PasswordStoreChangeList PasswordStoreMac::RemoveLoginsCreatedBetweenImpl(
9465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const base::Time& delete_begin, const base::Time& delete_end) {
9475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  PasswordStoreChangeList changes;
9485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<PasswordForm*> forms;
9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (login_metadata_db_->GetLoginsCreatedBetween(delete_begin, delete_end,
9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                  &forms)) {
9515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (login_metadata_db_->RemoveLoginsCreatedBetween(delete_begin,
9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                       delete_end)) {
9535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // We can't delete from the Keychain by date because we may be sharing
9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // items with database entries that weren't in the delete range. Instead,
9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // we find all the Keychain items we own but aren't using any more and
9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // delete those.
9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::vector<PasswordForm*> orphan_keychain_forms =
9585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          GetUnusedKeychainForms();
9595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // This is inefficient, since we have to re-look-up each keychain item
9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // one at a time to delete it even though the search step already had a
9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // list of Keychain item references. If this turns out to be noticeably
9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // slow we'll need to rearchitect to allow the search and deletion steps
9635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // to share.
9645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      RemoveKeychainForms(orphan_keychain_forms);
9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      STLDeleteElements(&orphan_keychain_forms);
9665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (std::vector<PasswordForm*>::const_iterator it = forms.begin();
9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           it != forms.end(); ++it) {
9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        changes.push_back(PasswordStoreChange(PasswordStoreChange::REMOVE,
9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              **it));
9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
9724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      LogStatsForBulkDeletion(changes.size());
9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return changes;
9765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void PasswordStoreMac::GetLoginsImpl(
97958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const autofill::PasswordForm& form,
9805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    AuthorizationPromptPolicy prompt_policy,
9812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const ConsumerCallbackRunner& callback_runner) {
9825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  chrome::ScopedSecKeychainSetUserInteractionAllowed user_interaction_allowed(
9835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      prompt_policy == ALLOW_PROMPT);
9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<PasswordForm*> database_forms;
9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  login_metadata_db_->GetLogins(form, &database_forms);
9875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Let's gather all signon realms we want to match with keychain entries.
9895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::set<std::string> realm_set;
9905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  realm_set.insert(form.signon_realm);
9915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (std::vector<PasswordForm*>::const_iterator db_form =
9925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           database_forms.begin();
9935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       db_form != database_forms.end();
9945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       ++db_form) {
9955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // TODO(vabr): We should not be getting different schemes here.
9965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // http://crbug.com/340112
9975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (form.scheme != (*db_form)->scheme)
9985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      continue;  // Forms with different schemes never match.
9995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& original_singon_realm((*db_form)->original_signon_realm);
10005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!original_singon_realm.empty())
10015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      realm_set.insert(original_singon_realm);
10025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
10035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::vector<PasswordForm*> keychain_forms;
10045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (std::set<std::string>::const_iterator realm = realm_set.begin();
10055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       realm != realm_set.end();
10065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       ++realm) {
10075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    MacKeychainPasswordFormAdapter keychain_adapter(keychain_.get());
10085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::vector<PasswordForm*> temp_keychain_forms =
10095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        keychain_adapter.PasswordsFillingForm(*realm, form.scheme);
10105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    keychain_forms.insert(keychain_forms.end(),
10115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                          temp_keychain_forms.begin(),
10125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                          temp_keychain_forms.end());
10135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
10145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
10152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<PasswordForm*> matched_forms;
10165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  internal_keychain_helpers::MergePasswordForms(&keychain_forms,
10175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                &database_forms,
10182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                &matched_forms);
10195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Strip any blacklist entries out of the unused Keychain array, then take
10215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // all the entries that are left (which we can use as imported passwords).
10225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<PasswordForm*> keychain_blacklist_forms =
10235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      internal_keychain_helpers::ExtractBlacklistForms(&keychain_forms);
10242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  matched_forms.insert(matched_forms.end(),
10252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                       keychain_forms.begin(),
10262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                       keychain_forms.end());
10275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  keychain_forms.clear();
10285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STLDeleteElements(&keychain_blacklist_forms);
10295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Clean up any orphaned database entries.
10315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RemoveDatabaseForms(database_forms);
10325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STLDeleteElements(&database_forms);
10335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  callback_runner.Run(matched_forms);
10355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PasswordStoreMac::GetBlacklistLoginsImpl(GetLoginsRequest* request) {
10385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  FillBlacklistLogins(request->result());
10395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ForwardLoginsResult(request);
10405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PasswordStoreMac::GetAutofillableLoginsImpl(GetLoginsRequest* request) {
10435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  FillAutofillableLogins(request->result());
10445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ForwardLoginsResult(request);
10455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PasswordStoreMac::FillAutofillableLogins(
10485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         std::vector<PasswordForm*>* forms) {
104990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(thread_->message_loop() == base::MessageLoop::current());
10505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<PasswordForm*> database_forms;
10525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  login_metadata_db_->GetAutofillableLogins(&database_forms);
10535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<PasswordForm*> merged_forms =
10555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      internal_keychain_helpers::GetPasswordsForForms(*keychain_,
10565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                      &database_forms);
10575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Clean up any orphaned database entries.
10595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RemoveDatabaseForms(database_forms);
10605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STLDeleteElements(&database_forms);
10615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  forms->insert(forms->end(), merged_forms.begin(), merged_forms.end());
10635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
10645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PasswordStoreMac::FillBlacklistLogins(
10675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         std::vector<PasswordForm*>* forms) {
106890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(thread_->message_loop() == base::MessageLoop::current());
10695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return login_metadata_db_->GetBlacklistLogins(forms);
10705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PasswordStoreMac::AddToKeychainIfNecessary(const PasswordForm& form) {
10735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (form.blacklisted_by_user) {
10745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
10755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MacKeychainPasswordFormAdapter keychainAdapter(keychain_.get());
10775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return keychainAdapter.AddPassword(form);
10785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PasswordStoreMac::DatabaseHasFormMatchingKeychainForm(
108158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const autofill::PasswordForm& form) {
10825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool has_match = false;
10835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<PasswordForm*> database_forms;
10845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  login_metadata_db_->GetLogins(form, &database_forms);
10855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<PasswordForm*>::iterator i = database_forms.begin();
10865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != database_forms.end(); ++i) {
10875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Below we filter out forms with non-empty original_signon_realm, because
10885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // those signal fuzzy matches, and we are only interested in exact ones.
10895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if ((*i)->original_signon_realm.empty() &&
10905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        internal_keychain_helpers::FormsMatchForMerge(
10915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            form, **i, internal_keychain_helpers::STRICT_FORM_MATCH) &&
10925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        (*i)->origin == form.origin) {
10935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      has_match = true;
10945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
10955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STLDeleteElements(&database_forms);
10985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return has_match;
10995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::vector<PasswordForm*> PasswordStoreMac::GetUnusedKeychainForms() {
11025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<PasswordForm*> database_forms;
11035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  login_metadata_db_->GetAutofillableLogins(&database_forms);
11045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MacKeychainPasswordFormAdapter owned_keychain_adapter(keychain_.get());
11065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  owned_keychain_adapter.SetFindsOnlyOwnedItems(true);
11075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<PasswordForm*> owned_keychain_forms =
11085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      owned_keychain_adapter.GetAllPasswordFormPasswords();
11095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Run a merge; anything left in owned_keychain_forms when we are done no
11115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // longer has a matching database entry.
11125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<PasswordForm*> merged_forms;
11135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  internal_keychain_helpers::MergePasswordForms(&owned_keychain_forms,
11145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                &database_forms,
11155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                &merged_forms);
11165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STLDeleteElements(&merged_forms);
11175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STLDeleteElements(&database_forms);
11185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return owned_keychain_forms;
11205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PasswordStoreMac::RemoveDatabaseForms(
11235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<PasswordForm*>& forms) {
11245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<PasswordForm*>::const_iterator i = forms.begin();
11255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != forms.end(); ++i) {
11265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    login_metadata_db_->RemoveLogin(**i);
11275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PasswordStoreMac::RemoveKeychainForms(
11315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<PasswordForm*>& forms) {
11325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MacKeychainPasswordFormAdapter owned_keychain_adapter(keychain_.get());
11335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  owned_keychain_adapter.SetFindsOnlyOwnedItems(true);
11345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<PasswordForm*>::const_iterator i = forms.begin();
11355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != forms.end(); ++i) {
11365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    owned_keychain_adapter.RemovePassword(**i);
11375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1139