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