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