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