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