- add sources.
[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/chrome_notification_types.h"
23 #include "chrome/browser/password_manager/login_database.h"
24 #include "chrome/browser/password_manager/password_store_change.h"
25 #include "content/public/browser/notification_service.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     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         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   // We never merge blacklist entries between our store and the keychain.
362   if (form_a.blacklisted_by_user || form_b.blacklisted_by_user) {
363     return false;
364   }
365   return form_a.scheme == form_b.scheme &&
366          form_a.signon_realm == form_b.signon_realm &&
367          form_a.username_value == form_b.username_value;
368 }
369
370 // Returns an the best match for |form| from |keychain_forms|, or NULL if there
371 // is no suitable match.
372 PasswordForm* BestKeychainFormForForm(
373     const PasswordForm& base_form,
374     const std::vector<PasswordForm*>* keychain_forms) {
375   PasswordForm* partial_match = NULL;
376   for (std::vector<PasswordForm*>::const_iterator i = keychain_forms->begin();
377        i != keychain_forms->end(); ++i) {
378     // TODO(stuartmorgan): We should really be scoring path matches and picking
379     // the best, rather than just checking exact-or-not (although in practice
380     // keychain items with paths probably came from us).
381     if (FormsMatchForMerge(base_form, *(*i))) {
382       if (base_form.origin == (*i)->origin) {
383         return *i;
384       } else if (!partial_match) {
385         partial_match = *i;
386       }
387     }
388   }
389   return partial_match;
390 }
391
392 // Returns entries from |forms| that are blacklist entries, after removing
393 // them from |forms|.
394 std::vector<PasswordForm*> ExtractBlacklistForms(
395     std::vector<PasswordForm*>* forms) {
396   std::vector<PasswordForm*> blacklist_forms;
397   for (std::vector<PasswordForm*>::iterator i = forms->begin();
398        i != forms->end();) {
399     PasswordForm* form = *i;
400     if (form->blacklisted_by_user) {
401       blacklist_forms.push_back(form);
402       i = forms->erase(i);
403     } else {
404       ++i;
405     }
406   }
407   return blacklist_forms;
408 }
409
410 // Deletes and removes from v any element that exists in s.
411 template <class T>
412 void DeleteVectorElementsInSet(std::vector<T*>* v, const std::set<T*>& s) {
413   for (typename std::vector<T*>::iterator i = v->begin(); i != v->end();) {
414     T* element = *i;
415     if (s.find(element) != s.end()) {
416       delete element;
417       i = v->erase(i);
418     } else {
419       ++i;
420     }
421   }
422 }
423
424 void MergePasswordForms(std::vector<PasswordForm*>* keychain_forms,
425                         std::vector<PasswordForm*>* database_forms,
426                         std::vector<PasswordForm*>* merged_forms) {
427   // Pull out the database blacklist items, since they are used as-is rather
428   // than being merged with keychain forms.
429   std::vector<PasswordForm*> database_blacklist_forms =
430       ExtractBlacklistForms(database_forms);
431
432   // Merge the normal entries.
433   std::set<PasswordForm*> used_keychain_forms;
434   for (std::vector<PasswordForm*>::iterator i = database_forms->begin();
435        i != database_forms->end();) {
436     PasswordForm* db_form = *i;
437     PasswordForm* best_match = BestKeychainFormForForm(*db_form,
438                                                        keychain_forms);
439     if (best_match) {
440       used_keychain_forms.insert(best_match);
441       db_form->password_value = best_match->password_value;
442       merged_forms->push_back(db_form);
443       i = database_forms->erase(i);
444     } else {
445       ++i;
446     }
447   }
448
449   // Add in the blacklist entries from the database.
450   merged_forms->insert(merged_forms->end(),
451                        database_blacklist_forms.begin(),
452                        database_blacklist_forms.end());
453
454   // Clear out all the Keychain entries we used.
455   DeleteVectorElementsInSet(keychain_forms, used_keychain_forms);
456 }
457
458 std::vector<ItemFormPair> ExtractAllKeychainItemAttributesIntoPasswordForms(
459     std::vector<SecKeychainItemRef>* keychain_items,
460     const AppleKeychain& keychain) {
461   DCHECK(keychain_items);
462   MacKeychainPasswordFormAdapter keychain_adapter(&keychain);
463   *keychain_items = keychain_adapter.GetAllPasswordFormKeychainItems();
464   std::vector<ItemFormPair> item_form_pairs;
465   for (std::vector<SecKeychainItemRef>::iterator i = keychain_items->begin();
466        i != keychain_items->end(); ++i) {
467     PasswordForm* form_without_password = new PasswordForm();
468     internal_keychain_helpers::FillPasswordFormFromKeychainItem(
469         keychain,
470         *i,
471         form_without_password,
472         false);  // Load password attributes, but not password data.
473     item_form_pairs.push_back(std::make_pair(&(*i), form_without_password));
474   }
475   return item_form_pairs;
476 }
477
478 std::vector<PasswordForm*> GetPasswordsForForms(
479     const AppleKeychain& keychain,
480     std::vector<PasswordForm*>* database_forms) {
481   // First load the attributes of all items in the keychain without loading
482   // their password data, and then match items in |database_forms| against them.
483   // This avoids individually searching through the keychain for passwords
484   // matching each form in |database_forms|, and results in a significant
485   // performance gain, replacing O(N) keychain search operations with a single
486   // operation that loads all keychain items, and then selective reads of only
487   // the relevant passwords. See crbug.com/263685.
488   std::vector<SecKeychainItemRef> keychain_items;
489   std::vector<ItemFormPair> item_form_pairs =
490       ExtractAllKeychainItemAttributesIntoPasswordForms(&keychain_items,
491                                                         keychain);
492
493   // Next, compare the attributes of the PasswordForms in |database_forms|
494   // against those in |item_form_pairs|, and extract password data for each
495   // matching PasswordForm using its corresponding SecKeychainItemRef.
496   std::vector<PasswordForm*> merged_forms;
497   for (std::vector<PasswordForm*>::iterator i = database_forms->begin();
498        i != database_forms->end();) {
499     std::vector<PasswordForm*> db_form_container(1, *i);
500     std::vector<PasswordForm*> keychain_matches =
501         ExtractPasswordsMergeableWithForm(keychain, item_form_pairs, **i);
502     MergePasswordForms(&keychain_matches, &db_form_container, &merged_forms);
503     if (db_form_container.empty()) {
504       i = database_forms->erase(i);
505     } else {
506       ++i;
507     }
508     STLDeleteElements(&keychain_matches);
509   }
510
511   // Clean up temporary PasswordForms and SecKeychainItemRefs.
512   STLDeleteContainerPairSecondPointers(item_form_pairs.begin(),
513                                        item_form_pairs.end());
514   for (std::vector<SecKeychainItemRef>::iterator i = keychain_items.begin();
515        i != keychain_items.end(); ++i) {
516     keychain.Free(*i);
517   }
518   return merged_forms;
519 }
520
521 // TODO(stuartmorgan): signon_realm for proxies is not yet supported.
522 bool ExtractSignonRealmComponents(
523     const std::string& signon_realm, std::string* server, int* port,
524     bool* is_secure, std::string* security_domain) {
525   // The signon_realm will be the Origin portion of a URL for an HTML form,
526   // and the same but with the security domain as a path for HTTP auth.
527   GURL realm_as_url(signon_realm);
528   if (!realm_as_url.is_valid()) {
529     return false;
530   }
531
532   if (server)
533     *server = realm_as_url.host();
534   if (is_secure)
535     *is_secure = realm_as_url.SchemeIsSecure();
536   if (port)
537     *port = realm_as_url.has_port() ? atoi(realm_as_url.port().c_str()) : 0;
538   if (security_domain) {
539     // Strip the leading '/' off of the path to get the security domain.
540     if (realm_as_url.path().length() > 0)
541       *security_domain = realm_as_url.path().substr(1);
542     else
543       security_domain->clear();
544   }
545   return true;
546 }
547
548 bool FormIsValidAndMatchesOtherForm(const PasswordForm& query_form,
549                                     const PasswordForm& other_form) {
550   std::string server;
551   std::string security_domain;
552   int port;
553   bool is_secure;
554   if (!ExtractSignonRealmComponents(query_form.signon_realm, &server, &port,
555                                     &is_secure, &security_domain)) {
556     return false;
557   }
558   return internal_keychain_helpers::FormsMatchForMerge(query_form, other_form);
559 }
560
561 std::vector<PasswordForm*> ExtractPasswordsMergeableWithForm(
562     const AppleKeychain& keychain,
563     const std::vector<ItemFormPair>& item_form_pairs,
564     const PasswordForm& query_form) {
565   std::vector<PasswordForm*> matches;
566   for (std::vector<ItemFormPair>::const_iterator i = item_form_pairs.begin();
567        i != item_form_pairs.end(); ++i) {
568     if (FormIsValidAndMatchesOtherForm(query_form, *(i->second))) {
569       // Create a new object, since the caller is responsible for deleting the
570       // returned forms.
571       scoped_ptr<PasswordForm> form_with_password(new PasswordForm());
572       internal_keychain_helpers::FillPasswordFormFromKeychainItem(
573           keychain,
574           *(i->first),
575           form_with_password.get(),
576           true);  // Load password attributes and data.
577       // Do not include blacklisted items found in the keychain.
578       if (!form_with_password->blacklisted_by_user)
579         matches.push_back(form_with_password.release());
580     }
581   }
582   return matches;
583 }
584
585 }  // namespace internal_keychain_helpers
586
587 #pragma mark -
588
589 MacKeychainPasswordFormAdapter::MacKeychainPasswordFormAdapter(
590     const AppleKeychain* keychain)
591     : keychain_(keychain), finds_only_owned_(false) {
592 }
593
594 std::vector<PasswordForm*>
595     MacKeychainPasswordFormAdapter::PasswordsFillingForm(
596         const PasswordForm& query_form) {
597   std::vector<SecKeychainItemRef> keychain_items =
598       MatchingKeychainItems(query_form.signon_realm, query_form.scheme,
599                             NULL, NULL);
600
601   return ConvertKeychainItemsToForms(&keychain_items);
602 }
603
604 PasswordForm* MacKeychainPasswordFormAdapter::PasswordExactlyMatchingForm(
605     const PasswordForm& query_form) {
606   SecKeychainItemRef keychain_item = KeychainItemForForm(query_form);
607   if (keychain_item) {
608     PasswordForm* form = new PasswordForm();
609     internal_keychain_helpers::FillPasswordFormFromKeychainItem(*keychain_,
610                                                                 keychain_item,
611                                                                 form,
612                                                                 true);
613     keychain_->Free(keychain_item);
614     return form;
615   }
616   return NULL;
617 }
618
619 bool MacKeychainPasswordFormAdapter::HasPasswordsMergeableWithForm(
620     const PasswordForm& query_form) {
621   std::string username = UTF16ToUTF8(query_form.username_value);
622   std::vector<SecKeychainItemRef> matches =
623       MatchingKeychainItems(query_form.signon_realm, query_form.scheme,
624                             NULL, username.c_str());
625   for (std::vector<SecKeychainItemRef>::iterator i = matches.begin();
626        i != matches.end(); ++i) {
627     keychain_->Free(*i);
628   }
629
630   return !matches.empty();
631 }
632
633 std::vector<SecKeychainItemRef>
634     MacKeychainPasswordFormAdapter::GetAllPasswordFormKeychainItems() {
635   SecAuthenticationType supported_auth_types[] = {
636     kSecAuthenticationTypeHTMLForm,
637     kSecAuthenticationTypeHTTPBasic,
638     kSecAuthenticationTypeHTTPDigest,
639   };
640
641   std::vector<SecKeychainItemRef> matches;
642   for (unsigned int i = 0; i < arraysize(supported_auth_types); ++i) {
643     KeychainSearch keychain_search(*keychain_);
644     keychain_search.Init(NULL, 0, kSecProtocolTypeAny, supported_auth_types[i],
645                          NULL, NULL, NULL, CreatorCodeForSearch());
646     keychain_search.FindMatchingItems(&matches);
647   }
648   return matches;
649 }
650
651 std::vector<PasswordForm*>
652     MacKeychainPasswordFormAdapter::GetAllPasswordFormPasswords() {
653   std::vector<SecKeychainItemRef> items = GetAllPasswordFormKeychainItems();
654   return ConvertKeychainItemsToForms(&items);
655 }
656
657 bool MacKeychainPasswordFormAdapter::AddPassword(const PasswordForm& form) {
658   // We should never be trying to store a blacklist in the keychain.
659   DCHECK(!form.blacklisted_by_user);
660
661   std::string server;
662   std::string security_domain;
663   int port;
664   bool is_secure;
665   if (!internal_keychain_helpers::ExtractSignonRealmComponents(
666            form.signon_realm, &server, &port, &is_secure, &security_domain)) {
667     return false;
668   }
669   std::string username = UTF16ToUTF8(form.username_value);
670   std::string password = UTF16ToUTF8(form.password_value);
671   std::string path = form.origin.path();
672   SecProtocolType protocol = is_secure ? kSecProtocolTypeHTTPS
673                                        : kSecProtocolTypeHTTP;
674   SecKeychainItemRef new_item = NULL;
675   OSStatus result = keychain_->AddInternetPassword(
676       NULL, server.size(), server.c_str(),
677       security_domain.size(), security_domain.c_str(),
678       username.size(), username.c_str(),
679       path.size(), path.c_str(),
680       port, protocol, AuthTypeForScheme(form.scheme),
681       password.size(), password.c_str(), &new_item);
682
683   if (result == noErr) {
684     SetKeychainItemCreatorCode(new_item,
685                                base::mac::CreatorCodeForApplication());
686     keychain_->Free(new_item);
687   } else if (result == errSecDuplicateItem) {
688     // If we collide with an existing item, find and update it instead.
689     SecKeychainItemRef existing_item = KeychainItemForForm(form);
690     if (!existing_item) {
691       return false;
692     }
693     bool changed = SetKeychainItemPassword(existing_item, password);
694     keychain_->Free(existing_item);
695     return changed;
696   }
697
698   return result == noErr;
699 }
700
701 bool MacKeychainPasswordFormAdapter::RemovePassword(const PasswordForm& form) {
702   SecKeychainItemRef keychain_item = KeychainItemForForm(form);
703   if (keychain_item == NULL)
704     return false;
705   OSStatus result = keychain_->ItemDelete(keychain_item);
706   keychain_->Free(keychain_item);
707   return result == noErr;
708 }
709
710 void MacKeychainPasswordFormAdapter::SetFindsOnlyOwnedItems(
711     bool finds_only_owned) {
712   finds_only_owned_ = finds_only_owned;
713 }
714
715 std::vector<PasswordForm*>
716     MacKeychainPasswordFormAdapter::ConvertKeychainItemsToForms(
717         std::vector<SecKeychainItemRef>* items) {
718   std::vector<PasswordForm*> keychain_forms;
719   for (std::vector<SecKeychainItemRef>::const_iterator i = items->begin();
720        i != items->end(); ++i) {
721     PasswordForm* form = new PasswordForm();
722     if (internal_keychain_helpers::FillPasswordFormFromKeychainItem(
723             *keychain_, *i, form, true)) {
724       keychain_forms.push_back(form);
725     }
726     keychain_->Free(*i);
727   }
728   items->clear();
729   return keychain_forms;
730 }
731
732 SecKeychainItemRef MacKeychainPasswordFormAdapter::KeychainItemForForm(
733     const PasswordForm& form) {
734   // We don't store blacklist entries in the keychain, so the answer to "what
735   // Keychain item goes with this form" is always "nothing" for blacklists.
736   if (form.blacklisted_by_user) {
737     return NULL;
738   }
739
740   std::string path = form.origin.path();
741   std::string username = UTF16ToUTF8(form.username_value);
742   std::vector<SecKeychainItemRef> matches = MatchingKeychainItems(
743       form.signon_realm, form.scheme, path.c_str(), username.c_str());
744
745   if (matches.empty()) {
746     return NULL;
747   }
748   // Free all items after the first, since we won't be returning them.
749   for (std::vector<SecKeychainItemRef>::iterator i = matches.begin() + 1;
750        i != matches.end(); ++i) {
751     keychain_->Free(*i);
752   }
753   return matches[0];
754 }
755
756 std::vector<SecKeychainItemRef>
757     MacKeychainPasswordFormAdapter::MatchingKeychainItems(
758         const std::string& signon_realm,
759         autofill::PasswordForm::Scheme scheme,
760         const char* path, const char* username) {
761   std::vector<SecKeychainItemRef> matches;
762
763   std::string server;
764   std::string security_domain;
765   int port;
766   bool is_secure;
767   if (!internal_keychain_helpers::ExtractSignonRealmComponents(
768            signon_realm, &server, &port, &is_secure, &security_domain)) {
769     // TODO(stuartmorgan): Proxies will currently fail here, since their
770     // signon_realm is not a URL. We need to detect the proxy case and handle
771     // it specially.
772     return matches;
773   }
774   SecProtocolType protocol = is_secure ? kSecProtocolTypeHTTPS
775                                        : kSecProtocolTypeHTTP;
776   SecAuthenticationType auth_type = AuthTypeForScheme(scheme);
777   const char* auth_domain = (scheme == PasswordForm::SCHEME_HTML) ?
778       NULL : security_domain.c_str();
779   KeychainSearch keychain_search(*keychain_);
780   keychain_search.Init(server.c_str(), port, protocol, auth_type,
781                        auth_domain, path, username, CreatorCodeForSearch());
782   keychain_search.FindMatchingItems(&matches);
783   return matches;
784 }
785
786 // Returns the Keychain SecAuthenticationType type corresponding to |scheme|.
787 SecAuthenticationType MacKeychainPasswordFormAdapter::AuthTypeForScheme(
788     PasswordForm::Scheme scheme) {
789   switch (scheme) {
790     case PasswordForm::SCHEME_HTML:   return kSecAuthenticationTypeHTMLForm;
791     case PasswordForm::SCHEME_BASIC:  return kSecAuthenticationTypeHTTPBasic;
792     case PasswordForm::SCHEME_DIGEST: return kSecAuthenticationTypeHTTPDigest;
793     case PasswordForm::SCHEME_OTHER:  return kSecAuthenticationTypeDefault;
794   }
795   NOTREACHED();
796   return kSecAuthenticationTypeDefault;
797 }
798
799 bool MacKeychainPasswordFormAdapter::SetKeychainItemPassword(
800     const SecKeychainItemRef& keychain_item, const std::string& password) {
801   OSStatus result = keychain_->ItemModifyAttributesAndData(keychain_item, NULL,
802                                                            password.size(),
803                                                            password.c_str());
804   return result == noErr;
805 }
806
807 bool MacKeychainPasswordFormAdapter::SetKeychainItemCreatorCode(
808     const SecKeychainItemRef& keychain_item, OSType creator_code) {
809   SecKeychainAttribute attr = { kSecCreatorItemAttr, sizeof(creator_code),
810                                 &creator_code };
811   SecKeychainAttributeList attrList = { 1, &attr };
812   OSStatus result = keychain_->ItemModifyAttributesAndData(keychain_item,
813                                                            &attrList, 0, NULL);
814   return result == noErr;
815 }
816
817 OSType MacKeychainPasswordFormAdapter::CreatorCodeForSearch() {
818   return finds_only_owned_ ? base::mac::CreatorCodeForApplication() : 0;
819 }
820
821 #pragma mark -
822
823 PasswordStoreMac::PasswordStoreMac(AppleKeychain* keychain,
824                                    LoginDatabase* login_db)
825     : keychain_(keychain), login_metadata_db_(login_db) {
826   DCHECK(keychain_.get());
827   DCHECK(login_metadata_db_.get());
828 }
829
830 PasswordStoreMac::~PasswordStoreMac() {
831   if (thread_.get()) {
832     thread_->message_loop()->DeleteSoon(FROM_HERE,
833                                         notification_service_.release());
834   }
835 }
836
837 bool PasswordStoreMac::Init() {
838   thread_.reset(new base::Thread("Chrome_PasswordStore_Thread"));
839
840   if (!thread_->Start()) {
841     thread_.reset(NULL);
842     return false;
843   }
844   ScheduleTask(base::Bind(&PasswordStoreMac::CreateNotificationService, this));
845   return PasswordStore::Init();
846 }
847
848 void PasswordStoreMac::ShutdownOnUIThread() {
849 }
850
851 // Mac stores passwords in the system keychain, which can block for an
852 // arbitrarily long time (most notably, it can block on user confirmation
853 // from a dialog). Use a dedicated thread to avoid blocking DB thread.
854 bool PasswordStoreMac::ScheduleTask(const base::Closure& task) {
855   if (thread_.get()) {
856     thread_->message_loop()->PostTask(FROM_HERE, task);
857     return true;
858   }
859   return false;
860 }
861
862 void PasswordStoreMac::ReportMetricsImpl() {
863   login_metadata_db_->ReportMetrics();
864 }
865
866 void PasswordStoreMac::AddLoginImpl(const PasswordForm& form) {
867   if (AddToKeychainIfNecessary(form)) {
868     if (login_metadata_db_->AddLogin(form)) {
869       PasswordStoreChangeList changes;
870       changes.push_back(PasswordStoreChange(PasswordStoreChange::ADD, form));
871       content::NotificationService::current()->Notify(
872           chrome::NOTIFICATION_LOGINS_CHANGED,
873           content::Source<PasswordStore>(this),
874           content::Details<PasswordStoreChangeList>(&changes));
875     }
876   }
877 }
878
879 void PasswordStoreMac::UpdateLoginImpl(const PasswordForm& form) {
880   int update_count = 0;
881   if (!login_metadata_db_->UpdateLogin(form, &update_count))
882     return;
883
884   MacKeychainPasswordFormAdapter keychain_adapter(keychain_.get());
885   if (update_count == 0 &&
886       !keychain_adapter.HasPasswordsMergeableWithForm(form)) {
887     // If the password isn't in either the DB or the keychain, then it must have
888     // been deleted after autofill happened, and should not be re-added.
889     return;
890   }
891
892   // The keychain add will update if there is a collision and add if there
893   // isn't, which is the behavior we want, so there's no separate update call.
894   if (AddToKeychainIfNecessary(form)) {
895     PasswordStoreChangeList changes;
896     if (update_count == 0) {
897       if (login_metadata_db_->AddLogin(form)) {
898         changes.push_back(PasswordStoreChange(PasswordStoreChange::ADD,
899                                               form));
900       }
901     } else {
902       changes.push_back(PasswordStoreChange(PasswordStoreChange::UPDATE,
903                                             form));
904     }
905     if (!changes.empty()) {
906       content::NotificationService::current()->Notify(
907           chrome::NOTIFICATION_LOGINS_CHANGED,
908           content::Source<PasswordStore>(this),
909           content::Details<PasswordStoreChangeList>(&changes));
910     }
911   }
912 }
913
914 void PasswordStoreMac::RemoveLoginImpl(const PasswordForm& form) {
915   if (login_metadata_db_->RemoveLogin(form)) {
916     // See if we own a Keychain item associated with this item. We can do an
917     // exact search rather than messing around with trying to do fuzzy matching
918     // because passwords that we created will always have an exact-match
919     // database entry.
920     // (If a user does lose their profile but not their keychain we'll treat the
921     // entries we find like other imported entries anyway, so it's reasonable to
922     // handle deletes on them the way we would for an imported item.)
923     MacKeychainPasswordFormAdapter owned_keychain_adapter(keychain_.get());
924     owned_keychain_adapter.SetFindsOnlyOwnedItems(true);
925     PasswordForm* owned_password_form =
926         owned_keychain_adapter.PasswordExactlyMatchingForm(form);
927     if (owned_password_form) {
928       // If we don't have other forms using it (i.e., a form differing only by
929       // the names of the form elements), delete the keychain entry.
930       if (!DatabaseHasFormMatchingKeychainForm(form)) {
931         owned_keychain_adapter.RemovePassword(form);
932       }
933     }
934
935     PasswordStoreChangeList changes;
936     changes.push_back(PasswordStoreChange(PasswordStoreChange::REMOVE, form));
937     content::NotificationService::current()->Notify(
938         chrome::NOTIFICATION_LOGINS_CHANGED,
939         content::Source<PasswordStore>(this),
940         content::Details<PasswordStoreChangeList>(&changes));
941   }
942 }
943
944 void PasswordStoreMac::RemoveLoginsCreatedBetweenImpl(
945     const base::Time& delete_begin, const base::Time& delete_end) {
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       PasswordStoreChangeList changes;
966       for (std::vector<PasswordForm*>::const_iterator it = forms.begin();
967            it != forms.end(); ++it) {
968         changes.push_back(PasswordStoreChange(PasswordStoreChange::REMOVE,
969                                               **it));
970       }
971       LogStatsForBulkDeletion(changes.size());
972       content::NotificationService::current()->Notify(
973           chrome::NOTIFICATION_LOGINS_CHANGED,
974           content::Source<PasswordStore>(this),
975           content::Details<PasswordStoreChangeList>(&changes));
976     }
977   }
978 }
979
980 void PasswordStoreMac::GetLoginsImpl(
981     const autofill::PasswordForm& form,
982     const ConsumerCallbackRunner& callback_runner) {
983   MacKeychainPasswordFormAdapter keychain_adapter(keychain_.get());
984   std::vector<PasswordForm*> keychain_forms =
985       keychain_adapter.PasswordsFillingForm(form);
986
987   std::vector<PasswordForm*> database_forms;
988   login_metadata_db_->GetLogins(form, &database_forms);
989
990   std::vector<PasswordForm*> matched_forms;
991   internal_keychain_helpers::MergePasswordForms(&keychain_forms,
992                                                 &database_forms,
993                                                 &matched_forms);
994
995   // Strip any blacklist entries out of the unused Keychain array, then take
996   // all the entries that are left (which we can use as imported passwords).
997   std::vector<PasswordForm*> keychain_blacklist_forms =
998       internal_keychain_helpers::ExtractBlacklistForms(&keychain_forms);
999   matched_forms.insert(matched_forms.end(),
1000                        keychain_forms.begin(),
1001                        keychain_forms.end());
1002   keychain_forms.clear();
1003   STLDeleteElements(&keychain_blacklist_forms);
1004
1005   // Clean up any orphaned database entries.
1006   RemoveDatabaseForms(database_forms);
1007   STLDeleteElements(&database_forms);
1008
1009   callback_runner.Run(matched_forms);
1010 }
1011
1012 void PasswordStoreMac::GetBlacklistLoginsImpl(GetLoginsRequest* request) {
1013   FillBlacklistLogins(&request->value);
1014   ForwardLoginsResult(request);
1015 }
1016
1017 void PasswordStoreMac::GetAutofillableLoginsImpl(GetLoginsRequest* request) {
1018   FillAutofillableLogins(&request->value);
1019   ForwardLoginsResult(request);
1020 }
1021
1022 bool PasswordStoreMac::FillAutofillableLogins(
1023          std::vector<PasswordForm*>* forms) {
1024   DCHECK(thread_->message_loop() == base::MessageLoop::current());
1025
1026   std::vector<PasswordForm*> database_forms;
1027   login_metadata_db_->GetAutofillableLogins(&database_forms);
1028
1029   std::vector<PasswordForm*> merged_forms =
1030       internal_keychain_helpers::GetPasswordsForForms(*keychain_,
1031                                                       &database_forms);
1032
1033   // Clean up any orphaned database entries.
1034   RemoveDatabaseForms(database_forms);
1035   STLDeleteElements(&database_forms);
1036
1037   forms->insert(forms->end(), merged_forms.begin(), merged_forms.end());
1038   return true;
1039 }
1040
1041 bool PasswordStoreMac::FillBlacklistLogins(
1042          std::vector<PasswordForm*>* forms) {
1043   DCHECK(thread_->message_loop() == base::MessageLoop::current());
1044   return login_metadata_db_->GetBlacklistLogins(forms);
1045 }
1046
1047 bool PasswordStoreMac::AddToKeychainIfNecessary(const PasswordForm& form) {
1048   if (form.blacklisted_by_user) {
1049     return true;
1050   }
1051   MacKeychainPasswordFormAdapter keychainAdapter(keychain_.get());
1052   return keychainAdapter.AddPassword(form);
1053 }
1054
1055 bool PasswordStoreMac::DatabaseHasFormMatchingKeychainForm(
1056     const autofill::PasswordForm& form) {
1057   bool has_match = false;
1058   std::vector<PasswordForm*> database_forms;
1059   login_metadata_db_->GetLogins(form, &database_forms);
1060   for (std::vector<PasswordForm*>::iterator i = database_forms.begin();
1061        i != database_forms.end(); ++i) {
1062     if (internal_keychain_helpers::FormsMatchForMerge(form, **i) &&
1063         (*i)->origin == form.origin) {
1064       has_match = true;
1065       break;
1066     }
1067   }
1068   STLDeleteElements(&database_forms);
1069   return has_match;
1070 }
1071
1072 std::vector<PasswordForm*> PasswordStoreMac::GetUnusedKeychainForms() {
1073   std::vector<PasswordForm*> database_forms;
1074   login_metadata_db_->GetAutofillableLogins(&database_forms);
1075
1076   MacKeychainPasswordFormAdapter owned_keychain_adapter(keychain_.get());
1077   owned_keychain_adapter.SetFindsOnlyOwnedItems(true);
1078   std::vector<PasswordForm*> owned_keychain_forms =
1079       owned_keychain_adapter.GetAllPasswordFormPasswords();
1080
1081   // Run a merge; anything left in owned_keychain_forms when we are done no
1082   // longer has a matching database entry.
1083   std::vector<PasswordForm*> merged_forms;
1084   internal_keychain_helpers::MergePasswordForms(&owned_keychain_forms,
1085                                                 &database_forms,
1086                                                 &merged_forms);
1087   STLDeleteElements(&merged_forms);
1088   STLDeleteElements(&database_forms);
1089
1090   return owned_keychain_forms;
1091 }
1092
1093 void PasswordStoreMac::RemoveDatabaseForms(
1094     const std::vector<PasswordForm*>& forms) {
1095   for (std::vector<PasswordForm*>::const_iterator i = forms.begin();
1096        i != forms.end(); ++i) {
1097     login_metadata_db_->RemoveLogin(**i);
1098   }
1099 }
1100
1101 void PasswordStoreMac::RemoveKeychainForms(
1102     const std::vector<PasswordForm*>& forms) {
1103   MacKeychainPasswordFormAdapter owned_keychain_adapter(keychain_.get());
1104   owned_keychain_adapter.SetFindsOnlyOwnedItems(true);
1105   for (std::vector<PasswordForm*>::const_iterator i = forms.begin();
1106        i != forms.end(); ++i) {
1107     owned_keychain_adapter.RemovePassword(**i);
1108   }
1109 }
1110
1111 void PasswordStoreMac::CreateNotificationService() {
1112   notification_service_.reset(content::NotificationService::Create());
1113 }