OLD | NEW |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/password_manager/password_store_mac.h" | 5 #include "chrome/browser/password_manager/password_store_mac.h" |
6 #include "chrome/browser/password_manager/password_store_mac_internal.h" | 6 #include "chrome/browser/password_manager/password_store_mac_internal.h" |
7 | 7 |
8 #include <CoreServices/CoreServices.h> | 8 #include <CoreServices/CoreServices.h> |
9 #include <string> | 9 #include <string> |
10 #include <vector> | 10 #include <vector> |
11 | 11 |
12 #include "base/logging.h" | 12 #include "base/logging.h" |
13 #include "base/stl_util-inl.h" | 13 #include "base/stl_util-inl.h" |
14 #include "base/string_util.h" | 14 #include "base/string_util.h" |
15 #include "base/time.h" | 15 #include "base/time.h" |
16 #include "chrome/browser/keychain_mac.h" | 16 #include "chrome/browser/keychain_mac.h" |
17 #include "chrome/browser/password_manager/login_database_mac.h" | 17 #include "chrome/browser/password_manager/login_database_mac.h" |
18 | 18 |
19 using webkit_glue::PasswordForm; | 19 using webkit_glue::PasswordForm; |
20 | 20 |
21 namespace internal_keychain_helpers { | |
22 | |
23 // Utility class to handle the details of constructing and running a keychain | 21 // Utility class to handle the details of constructing and running a keychain |
24 // search from a set of attributes. | 22 // search from a set of attributes. |
25 class KeychainSearch { | 23 class KeychainSearch { |
26 public: | 24 public: |
27 KeychainSearch(const MacKeychain& keychain); | 25 KeychainSearch(const MacKeychain& keychain); |
28 ~KeychainSearch(); | 26 ~KeychainSearch(); |
29 | 27 |
30 // Sets up a keycahin search based on an non "null" (NULL for char*, | 28 // Sets up a keycahin search based on an non "null" (NULL for char*, |
31 // The appropriate "Any" entry for other types) arguments. | 29 // The appropriate "Any" entry for other types) arguments. |
32 // | 30 // |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
146 // Consumer is responsible for deleting the forms when they are done. | 144 // Consumer is responsible for deleting the forms when they are done. |
147 items->push_back(keychain_item); | 145 items->push_back(keychain_item); |
148 } | 146 } |
149 | 147 |
150 keychain_->Free(search_ref_); | 148 keychain_->Free(search_ref_); |
151 search_ref_ = NULL; | 149 search_ref_ = NULL; |
152 } | 150 } |
153 | 151 |
154 #pragma mark - | 152 #pragma mark - |
155 | 153 |
| 154 // TODO(stuartmorgan): Convert most of this to private helpers in |
| 155 // MacKeychainPaswordFormAdapter once it has sufficient higher-level public |
| 156 // methods to provide test coverage. |
| 157 namespace internal_keychain_helpers { |
| 158 |
| 159 // Takes a PasswordForm's signon_realm and parses it into its component parts, |
| 160 // which are returned though the appropriate out parameters. |
| 161 // Returns true if it can be successfully parsed, in which case all out params |
| 162 // that are non-NULL will be set. If there is no port, port will be 0. |
| 163 // If the return value is false, the state of the our params is undefined. |
| 164 // |
156 // TODO(stuartmorgan): signon_realm for proxies is not yet supported. | 165 // TODO(stuartmorgan): signon_realm for proxies is not yet supported. |
157 bool ExtractSignonRealmComponents(const std::string& signon_realm, | 166 bool ExtractSignonRealmComponents(const std::string& signon_realm, |
158 std::string* server, int* port, | 167 std::string* server, int* port, |
159 bool* is_secure, | 168 bool* is_secure, |
160 std::string* security_domain) { | 169 std::string* security_domain) { |
161 // The signon_realm will be the Origin portion of a URL for an HTML form, | 170 // The signon_realm will be the Origin portion of a URL for an HTML form, |
162 // and the same but with the security domain as a path for HTTP auth. | 171 // and the same but with the security domain as a path for HTTP auth. |
163 GURL realm_as_url(signon_realm); | 172 GURL realm_as_url(signon_realm); |
164 if (!realm_as_url.is_valid()) { | 173 if (!realm_as_url.is_valid()) { |
165 return false; | 174 return false; |
166 } | 175 } |
167 | 176 |
168 if (server) | 177 if (server) |
169 *server = realm_as_url.host(); | 178 *server = realm_as_url.host(); |
170 if (is_secure) | 179 if (is_secure) |
171 *is_secure = realm_as_url.SchemeIsSecure(); | 180 *is_secure = realm_as_url.SchemeIsSecure(); |
172 if (port) | 181 if (port) |
173 *port = realm_as_url.has_port() ? atoi(realm_as_url.port().c_str()) : 0; | 182 *port = realm_as_url.has_port() ? atoi(realm_as_url.port().c_str()) : 0; |
174 if (security_domain) { | 183 if (security_domain) { |
175 // Strip the leading '/' off of the path to get the security domain. | 184 // Strip the leading '/' off of the path to get the security domain. |
176 *security_domain = realm_as_url.path().substr(1); | 185 *security_domain = realm_as_url.path().substr(1); |
177 } | 186 } |
178 return true; | 187 return true; |
179 } | 188 } |
180 | 189 |
| 190 // Returns a URL built from the given components. To create a URL without a |
| 191 // port, pass kAnyPort for the |port| parameter. |
181 GURL URLFromComponents(bool is_secure, const std::string& host, int port, | 192 GURL URLFromComponents(bool is_secure, const std::string& host, int port, |
182 const std::string& path) { | 193 const std::string& path) { |
183 GURL::Replacements url_components; | 194 GURL::Replacements url_components; |
184 std::string scheme(is_secure ? "https" : "http"); | 195 std::string scheme(is_secure ? "https" : "http"); |
185 url_components.SetSchemeStr(scheme); | 196 url_components.SetSchemeStr(scheme); |
186 url_components.SetHostStr(host); | 197 url_components.SetHostStr(host); |
187 std::string port_string; // Must remain in scope until after we do replacing. | 198 std::string port_string; // Must remain in scope until after we do replacing. |
188 if (port != kAnyPort) { | 199 if (port != kAnyPort) { |
189 std::ostringstream port_stringstream; | 200 std::ostringstream port_stringstream; |
190 port_stringstream << port; | 201 port_stringstream << port; |
191 port_string = port_stringstream.str(); | 202 port_string = port_stringstream.str(); |
192 url_components.SetPortStr(port_string); | 203 url_components.SetPortStr(port_string); |
193 } | 204 } |
194 url_components.SetPathStr(path); | 205 url_components.SetPathStr(path); |
195 | 206 |
196 GURL url("http://dummy.com"); // ReplaceComponents needs a valid URL. | 207 GURL url("http://dummy.com"); // ReplaceComponents needs a valid URL. |
197 return url.ReplaceComponents(url_components); | 208 return url.ReplaceComponents(url_components); |
198 } | 209 } |
199 | 210 |
200 // The time string is of the form "yyyyMMddHHmmss'Z", in UTC time. | 211 // Converts a Keychain time string to a Time object, returning true if |
| 212 // time_string_bytes was parsable. If the return value is false, the value of |
| 213 // |time| is unchanged. |
201 bool TimeFromKeychainTimeString(const char* time_string_bytes, | 214 bool TimeFromKeychainTimeString(const char* time_string_bytes, |
202 unsigned int byte_length, | 215 unsigned int byte_length, |
203 base::Time* time) { | 216 base::Time* time) { |
204 DCHECK(time); | 217 DCHECK(time); |
205 | 218 |
206 char* time_string = static_cast<char*>(malloc(byte_length + 1)); | 219 char* time_string = static_cast<char*>(malloc(byte_length + 1)); |
207 memcpy(time_string, time_string_bytes, byte_length); | 220 memcpy(time_string, time_string_bytes, byte_length); |
208 time_string[byte_length] = '\0'; | 221 time_string[byte_length] = '\0'; |
209 base::Time::Exploded exploded_time; | 222 base::Time::Exploded exploded_time; |
210 bzero(&exploded_time, sizeof(exploded_time)); | 223 bzero(&exploded_time, sizeof(exploded_time)); |
| 224 // The time string is of the form "yyyyMMddHHmmss'Z", in UTC time. |
211 int assignments = sscanf(time_string, "%4d%2d%2d%2d%2d%2dZ", | 225 int assignments = sscanf(time_string, "%4d%2d%2d%2d%2d%2dZ", |
212 &exploded_time.year, &exploded_time.month, | 226 &exploded_time.year, &exploded_time.month, |
213 &exploded_time.day_of_month, &exploded_time.hour, | 227 &exploded_time.day_of_month, &exploded_time.hour, |
214 &exploded_time.minute, &exploded_time.second); | 228 &exploded_time.minute, &exploded_time.second); |
215 free(time_string); | 229 free(time_string); |
216 | 230 |
217 if (assignments == 6) { | 231 if (assignments == 6) { |
218 *time = base::Time::FromUTCExploded(exploded_time); | 232 *time = base::Time::FromUTCExploded(exploded_time); |
219 return true; | 233 return true; |
220 } | 234 } |
221 return false; | 235 return false; |
222 } | 236 } |
223 | 237 |
| 238 // Returns the Keychain SecAuthenticationType type corresponding to |scheme|. |
224 SecAuthenticationType AuthTypeForScheme(PasswordForm::Scheme scheme) { | 239 SecAuthenticationType AuthTypeForScheme(PasswordForm::Scheme scheme) { |
225 switch (scheme) { | 240 switch (scheme) { |
226 case PasswordForm::SCHEME_HTML: return kSecAuthenticationTypeHTMLForm; | 241 case PasswordForm::SCHEME_HTML: return kSecAuthenticationTypeHTMLForm; |
227 case PasswordForm::SCHEME_BASIC: return kSecAuthenticationTypeHTTPBasic; | 242 case PasswordForm::SCHEME_BASIC: return kSecAuthenticationTypeHTTPBasic; |
228 case PasswordForm::SCHEME_DIGEST: return kSecAuthenticationTypeHTTPDigest; | 243 case PasswordForm::SCHEME_DIGEST: return kSecAuthenticationTypeHTTPDigest; |
229 case PasswordForm::SCHEME_OTHER: return kSecAuthenticationTypeDefault; | 244 case PasswordForm::SCHEME_OTHER: return kSecAuthenticationTypeDefault; |
230 } | 245 } |
231 NOTREACHED(); | 246 NOTREACHED(); |
232 return kSecAuthenticationTypeDefault; | 247 return kSecAuthenticationTypeDefault; |
233 } | 248 } |
234 | 249 |
| 250 // Returns the PasswordForm Scheme corresponding to |auth_type|. |
235 PasswordForm::Scheme SchemeForAuthType(SecAuthenticationType auth_type) { | 251 PasswordForm::Scheme SchemeForAuthType(SecAuthenticationType auth_type) { |
236 switch (auth_type) { | 252 switch (auth_type) { |
237 case kSecAuthenticationTypeHTMLForm: return PasswordForm::SCHEME_HTML; | 253 case kSecAuthenticationTypeHTMLForm: return PasswordForm::SCHEME_HTML; |
238 case kSecAuthenticationTypeHTTPBasic: return PasswordForm::SCHEME_BASIC; | 254 case kSecAuthenticationTypeHTTPBasic: return PasswordForm::SCHEME_BASIC; |
239 case kSecAuthenticationTypeHTTPDigest: return PasswordForm::SCHEME_DIGEST; | 255 case kSecAuthenticationTypeHTTPDigest: return PasswordForm::SCHEME_DIGEST; |
240 default: return PasswordForm::SCHEME_OTHER; | 256 default: return PasswordForm::SCHEME_OTHER; |
241 } | 257 } |
242 } | 258 } |
243 | 259 |
244 // Searches |keychain| for all items usable for the given signon_realm, and | 260 SecKeychainItemRef MatchingKeychainItem(const MacKeychain& keychain, |
245 // puts them in |items|. The caller is responsible for calling keychain->Free | 261 const PasswordForm& form) { |
246 // on each of them when it is finished with them. | |
247 void FindMatchingKeychainItems(const MacKeychain& keychain, | |
248 const std::string& signon_realm, | |
249 PasswordForm::Scheme scheme, | |
250 std::vector<SecKeychainItemRef>* items) { | |
251 // Construct a keychain search based on the signon_realm and scheme. | |
252 std::string server; | |
253 std::string security_domain; | |
254 int port; | |
255 bool is_secure; | |
256 if (!ExtractSignonRealmComponents(signon_realm, &server, &port, &is_secure, | |
257 &security_domain)) { | |
258 // TODO(stuartmorgan): Proxies will currently fail here, since their | |
259 // signon_realm is not a URL. We need to detect the proxy case and handle | |
260 // it specially. | |
261 return; | |
262 } | |
263 | |
264 SecProtocolType protocol = is_secure ? kSecProtocolTypeHTTPS | |
265 : kSecProtocolTypeHTTP; | |
266 SecAuthenticationType auth_type = AuthTypeForScheme(scheme); | |
267 | |
268 KeychainSearch keychain_search(keychain); | |
269 keychain_search.Init(server.c_str(), port, protocol, auth_type, | |
270 (scheme == PasswordForm::SCHEME_HTML) ? | |
271 NULL : security_domain.c_str(), | |
272 NULL, NULL); | |
273 keychain_search.FindMatchingItems(items); | |
274 } | |
275 | |
276 SecKeychainItemRef FindMatchingKeychainItem(const MacKeychain& keychain, | |
277 const PasswordForm& form) { | |
278 // We don't store blacklist entries in the keychain, so the answer to "what | 262 // We don't store blacklist entries in the keychain, so the answer to "what |
279 // Keychain item goes with this form" is always "nothing" for blacklists. | 263 // Keychain item goes with this form" is always "nothing" for blacklists. |
280 if (form.blacklisted_by_user) { | 264 if (form.blacklisted_by_user) { |
281 return NULL; | 265 return NULL; |
282 } | 266 } |
283 | 267 |
284 // Construct a keychain search based on all the unique attributes. | 268 // Construct a keychain search based on all the unique attributes. |
285 std::string server; | 269 std::string server; |
286 std::string security_domain; | 270 std::string security_domain; |
287 int port; | 271 int port; |
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
426 form->origin = URLFromComponents(form->ssl_valid, server, port, path); | 410 form->origin = URLFromComponents(form->ssl_valid, server, port, path); |
427 // TODO(stuartmorgan): Handle proxies, which need a different signon_realm | 411 // TODO(stuartmorgan): Handle proxies, which need a different signon_realm |
428 // format. | 412 // format. |
429 form->signon_realm = form->origin.GetOrigin().spec(); | 413 form->signon_realm = form->origin.GetOrigin().spec(); |
430 if (form->scheme != PasswordForm::SCHEME_HTML) { | 414 if (form->scheme != PasswordForm::SCHEME_HTML) { |
431 form->signon_realm.append(security_domain); | 415 form->signon_realm.append(security_domain); |
432 } | 416 } |
433 return true; | 417 return true; |
434 } | 418 } |
435 | 419 |
436 bool AddKeychainEntryForForm(const MacKeychain& keychain, | |
437 const PasswordForm& form) { | |
438 std::string server; | |
439 std::string security_domain; | |
440 int port; | |
441 bool is_secure; | |
442 if (!ExtractSignonRealmComponents(form.signon_realm, &server, &port, | |
443 &is_secure, &security_domain)) { | |
444 return false; | |
445 } | |
446 std::string username = WideToUTF8(form.username_value); | |
447 std::string password = WideToUTF8(form.password_value); | |
448 std::string path = form.origin.path(); | |
449 SecProtocolType protocol = is_secure ? kSecProtocolTypeHTTPS | |
450 : kSecProtocolTypeHTTP; | |
451 OSStatus result = keychain.AddInternetPassword( | |
452 NULL, server.size(), server.c_str(), | |
453 security_domain.size(), security_domain.c_str(), | |
454 username.size(), username.c_str(), | |
455 path.size(), path.c_str(), | |
456 port, protocol, AuthTypeForScheme(form.scheme), | |
457 password.size(), password.c_str(), NULL); | |
458 | |
459 // If we collide with an existing item, find and update it instead. | |
460 if (result == errSecDuplicateItem) { | |
461 SecKeychainItemRef existing_item = FindMatchingKeychainItem(keychain, form); | |
462 if (!existing_item) { | |
463 return false; | |
464 } | |
465 bool changed = SetKeychainItemPassword(keychain, existing_item, password); | |
466 keychain.Free(existing_item); | |
467 return changed; | |
468 } | |
469 | |
470 return (result == noErr); | |
471 } | |
472 | |
473 bool SetKeychainItemPassword(const MacKeychain& keychain, | |
474 const SecKeychainItemRef& keychain_item, | |
475 const std::string& password) { | |
476 OSStatus result = keychain.ItemModifyAttributesAndData(keychain_item, NULL, | |
477 password.size(), | |
478 password.c_str()); | |
479 return (result == noErr); | |
480 } | |
481 | |
482 bool FormsMatchForMerge(const PasswordForm& form_a, const PasswordForm& form_b, | 420 bool FormsMatchForMerge(const PasswordForm& form_a, const PasswordForm& form_b, |
483 bool* path_matches) { | 421 bool* path_matches) { |
484 // We never merge blacklist entries between our store and the keychain. | 422 // We never merge blacklist entries between our store and the keychain. |
485 if (form_a.blacklisted_by_user || form_b.blacklisted_by_user) { | 423 if (form_a.blacklisted_by_user || form_b.blacklisted_by_user) { |
486 return false; | 424 return false; |
487 } | 425 } |
488 bool matches = form_a.scheme == form_b.scheme && | 426 bool matches = form_a.scheme == form_b.scheme && |
489 form_a.signon_realm == form_b.signon_realm && | 427 form_a.signon_realm == form_b.signon_realm && |
490 form_a.username_value == form_b.username_value; | 428 form_a.username_value == form_b.username_value; |
491 if (matches && path_matches) { | 429 if (matches && path_matches) { |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
555 } else { | 493 } else { |
556 if (used_keychain_forms.find(keychain_form) == used_keychain_forms.end()) | 494 if (used_keychain_forms.find(keychain_form) == used_keychain_forms.end()) |
557 merged_forms->push_back(keychain_form); | 495 merged_forms->push_back(keychain_form); |
558 else | 496 else |
559 delete keychain_form; | 497 delete keychain_form; |
560 i = keychain_forms->erase(i); | 498 i = keychain_forms->erase(i); |
561 } | 499 } |
562 } | 500 } |
563 } | 501 } |
564 | 502 |
565 // Returns PasswordForms constructed from the given Keychain items. | 503 } // namespace internal_keychain_helpers |
| 504 |
| 505 #pragma mark - |
| 506 |
| 507 MacKeychainPasswordFormAdapter::MacKeychainPasswordFormAdapter( |
| 508 MacKeychain* keychain) : keychain_(keychain) { |
| 509 } |
| 510 |
| 511 // Returns PasswordForms for each keychain entry matching |form|. |
566 // Caller is responsible for deleting the returned forms. | 512 // Caller is responsible for deleting the returned forms. |
567 std::vector<PasswordForm*> CreateFormsFromKeychainItems( | 513 std::vector<PasswordForm*> |
568 const MacKeychain& keychain, | 514 MacKeychainPasswordFormAdapter::PasswordsMatchingForm( |
569 const std::vector<SecKeychainItemRef>& items) { | 515 const PasswordForm& query_form) { |
| 516 std::vector<SecKeychainItemRef> keychain_items = |
| 517 MatchingKeychainItems(query_form.signon_realm, query_form.scheme); |
| 518 |
| 519 std::vector<PasswordForm*> keychain_forms = |
| 520 CreateFormsFromKeychainItems(keychain_items); |
| 521 for (std::vector<SecKeychainItemRef>::iterator i = keychain_items.begin(); |
| 522 i != keychain_items.end(); ++i) { |
| 523 keychain_->Free(*i); |
| 524 } |
| 525 return keychain_forms; |
| 526 } |
| 527 |
| 528 bool MacKeychainPasswordFormAdapter::AddLogin(const PasswordForm& form) { |
| 529 std::string server; |
| 530 std::string security_domain; |
| 531 int port; |
| 532 bool is_secure; |
| 533 if (!internal_keychain_helpers::ExtractSignonRealmComponents( |
| 534 form.signon_realm, &server, &port, &is_secure, &security_domain)) { |
| 535 return false; |
| 536 } |
| 537 std::string username = WideToUTF8(form.username_value); |
| 538 std::string password = WideToUTF8(form.password_value); |
| 539 std::string path = form.origin.path(); |
| 540 SecProtocolType protocol = is_secure ? kSecProtocolTypeHTTPS |
| 541 : kSecProtocolTypeHTTP; |
| 542 OSStatus result = keychain_->AddInternetPassword( |
| 543 NULL, server.size(), server.c_str(), |
| 544 security_domain.size(), security_domain.c_str(), |
| 545 username.size(), username.c_str(), |
| 546 path.size(), path.c_str(), |
| 547 port, protocol, internal_keychain_helpers::AuthTypeForScheme(form.scheme), |
| 548 password.size(), password.c_str(), NULL); |
| 549 |
| 550 // If we collide with an existing item, find and update it instead. |
| 551 if (result == errSecDuplicateItem) { |
| 552 SecKeychainItemRef existing_item = |
| 553 internal_keychain_helpers::MatchingKeychainItem(*keychain_, form); |
| 554 if (!existing_item) { |
| 555 return false; |
| 556 } |
| 557 bool changed = SetKeychainItemPassword(existing_item, password); |
| 558 keychain_->Free(existing_item); |
| 559 return changed; |
| 560 } |
| 561 |
| 562 return (result == noErr); |
| 563 } |
| 564 |
| 565 std::vector<PasswordForm*> |
| 566 MacKeychainPasswordFormAdapter::CreateFormsFromKeychainItems( |
| 567 const std::vector<SecKeychainItemRef>& items) { |
570 std::vector<PasswordForm*> keychain_forms; | 568 std::vector<PasswordForm*> keychain_forms; |
571 for (std::vector<SecKeychainItemRef>::const_iterator i = items.begin(); | 569 for (std::vector<SecKeychainItemRef>::const_iterator i = items.begin(); |
572 i != items.end(); ++i) { | 570 i != items.end(); ++i) { |
573 PasswordForm* form = new PasswordForm(); | 571 PasswordForm* form = new PasswordForm(); |
574 if (FillPasswordFormFromKeychainItem(keychain, *i, form)) { | 572 if (internal_keychain_helpers::FillPasswordFormFromKeychainItem(*keychain_, |
| 573 *i, form)) { |
575 keychain_forms.push_back(form); | 574 keychain_forms.push_back(form); |
576 } | 575 } |
577 } | 576 } |
578 return keychain_forms; | 577 return keychain_forms; |
579 } | 578 } |
580 | 579 |
581 // Returns PasswordForms for each keychain entry matching |form|. | 580 // Searches |keychain| for all items usable for the given signon_realm, and |
582 // Caller is responsible for deleting the returned forms. | 581 // returns them. The caller is responsible for calling keychain->Free |
583 std::vector<PasswordForm*> KeychainFormsMatchingForm( | 582 // on each of them when it is finished with them. |
584 const MacKeychain& keychain, const PasswordForm& query_form) { | 583 std::vector<SecKeychainItemRef> |
585 std::vector<SecKeychainItemRef> keychain_items; | 584 MacKeychainPasswordFormAdapter::MatchingKeychainItems( |
586 FindMatchingKeychainItems(keychain, query_form.signon_realm, | 585 const std::string& signon_realm, PasswordForm::Scheme scheme) { |
587 query_form.scheme, &keychain_items); | 586 std::vector<SecKeychainItemRef> matches; |
| 587 // Construct a keychain search based on the signon_realm and scheme. |
| 588 std::string server; |
| 589 std::string security_domain; |
| 590 int port; |
| 591 bool is_secure; |
| 592 if (!internal_keychain_helpers::ExtractSignonRealmComponents( |
| 593 signon_realm, &server, &port, &is_secure, &security_domain)) { |
| 594 // TODO(stuartmorgan): Proxies will currently fail here, since their |
| 595 // signon_realm is not a URL. We need to detect the proxy case and handle |
| 596 // it specially. |
| 597 return matches; |
| 598 } |
588 | 599 |
589 std::vector<PasswordForm*> keychain_forms = | 600 SecProtocolType protocol = is_secure ? kSecProtocolTypeHTTPS |
590 CreateFormsFromKeychainItems(keychain, keychain_items); | 601 : kSecProtocolTypeHTTP; |
591 for (std::vector<SecKeychainItemRef>::iterator i = keychain_items.begin(); | 602 SecAuthenticationType auth_type = |
592 i != keychain_items.end(); ++i) { | 603 internal_keychain_helpers::AuthTypeForScheme(scheme); |
593 keychain.Free(*i); | 604 |
594 } | 605 KeychainSearch keychain_search(*keychain_); |
595 return keychain_forms; | 606 keychain_search.Init(server.c_str(), port, protocol, auth_type, |
| 607 (scheme == PasswordForm::SCHEME_HTML) ? |
| 608 NULL : security_domain.c_str(), |
| 609 NULL, NULL); |
| 610 keychain_search.FindMatchingItems(&matches); |
| 611 return matches; |
596 } | 612 } |
597 | 613 |
598 } // namespace internal_keychain_helpers | 614 bool MacKeychainPasswordFormAdapter::SetKeychainItemPassword( |
| 615 const SecKeychainItemRef& keychain_item, const std::string& password) { |
| 616 OSStatus result = keychain_->ItemModifyAttributesAndData(keychain_item, NULL, |
| 617 password.size(), |
| 618 password.c_str()); |
| 619 return (result == noErr); |
| 620 } |
599 | 621 |
600 #pragma mark - | 622 #pragma mark - |
601 | 623 |
602 PasswordStoreMac::PasswordStoreMac(MacKeychain* keychain, | 624 PasswordStoreMac::PasswordStoreMac(MacKeychain* keychain, |
603 LoginDatabaseMac* login_db) | 625 LoginDatabaseMac* login_db) |
604 : keychain_(keychain), login_metadata_db_(login_db) { | 626 : keychain_(keychain), login_metadata_db_(login_db) { |
605 DCHECK(keychain_.get()); | 627 DCHECK(keychain_.get()); |
606 DCHECK(login_metadata_db_.get()); | 628 DCHECK(login_metadata_db_.get()); |
607 } | 629 } |
608 | 630 |
609 PasswordStoreMac::~PasswordStoreMac() {} | 631 PasswordStoreMac::~PasswordStoreMac() {} |
610 | 632 |
611 void PasswordStoreMac::AddLoginImpl(const PasswordForm& form) { | 633 void PasswordStoreMac::AddLoginImpl(const PasswordForm& form) { |
612 NOTIMPLEMENTED(); | 634 NOTIMPLEMENTED(); |
613 } | 635 } |
614 | 636 |
615 void PasswordStoreMac::UpdateLoginImpl(const PasswordForm& form) { | 637 void PasswordStoreMac::UpdateLoginImpl(const PasswordForm& form) { |
616 NOTIMPLEMENTED(); | 638 NOTIMPLEMENTED(); |
617 } | 639 } |
618 | 640 |
619 void PasswordStoreMac::RemoveLoginImpl(const PasswordForm& form) { | 641 void PasswordStoreMac::RemoveLoginImpl(const PasswordForm& form) { |
620 NOTIMPLEMENTED(); | 642 NOTIMPLEMENTED(); |
621 } | 643 } |
622 | 644 |
623 void PasswordStoreMac::GetLoginsImpl(GetLoginsRequest* request) { | 645 void PasswordStoreMac::GetLoginsImpl(GetLoginsRequest* request) { |
| 646 MacKeychainPasswordFormAdapter keychainAdapter(keychain_.get()); |
624 std::vector<PasswordForm*> keychain_forms = | 647 std::vector<PasswordForm*> keychain_forms = |
625 internal_keychain_helpers::KeychainFormsMatchingForm(*keychain_, | 648 keychainAdapter.PasswordsMatchingForm(request->form); |
626 request->form); | |
627 | 649 |
628 std::vector<PasswordForm*> database_forms; | 650 std::vector<PasswordForm*> database_forms; |
629 login_metadata_db_->GetLogins(request->form, &database_forms); | 651 login_metadata_db_->GetLogins(request->form, &database_forms); |
630 | 652 |
631 std::vector<PasswordForm*> merged_forms; | 653 std::vector<PasswordForm*> merged_forms; |
632 internal_keychain_helpers::MergePasswordForms(&keychain_forms, | 654 internal_keychain_helpers::MergePasswordForms(&keychain_forms, |
633 &database_forms, | 655 &database_forms, |
634 &merged_forms); | 656 &merged_forms); |
635 | 657 |
636 // Clean up any orphaned database entries. | 658 // Clean up any orphaned database entries. |
637 for (std::vector<PasswordForm*>::iterator i = database_forms.begin(); | 659 for (std::vector<PasswordForm*>::iterator i = database_forms.begin(); |
638 i != database_forms.end(); ++i) { | 660 i != database_forms.end(); ++i) { |
639 login_metadata_db_->RemoveLogin(**i); | 661 login_metadata_db_->RemoveLogin(**i); |
640 } | 662 } |
641 // Delete the forms we aren't returning. | 663 // Delete the forms we aren't returning. |
642 STLDeleteElements(&database_forms); | 664 STLDeleteElements(&database_forms); |
643 STLDeleteElements(&keychain_forms); | 665 STLDeleteElements(&keychain_forms); |
644 | 666 |
645 NotifyConsumer(request, merged_forms); | 667 NotifyConsumer(request, merged_forms); |
646 } | 668 } |
OLD | NEW |