| OLD | NEW |
| 1 // Copyright (c) 2015 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2015 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/native_backend_libsecret.h" | 5 #include "chrome/browser/password_manager/native_backend_libsecret.h" |
| 6 | 6 |
| 7 #include <dlfcn.h> | 7 #include <dlfcn.h> |
| 8 #include <list> | 8 #include <list> |
| 9 | 9 |
| 10 #include "base/basictypes.h" | 10 #include "base/basictypes.h" |
| (...skipping 261 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 272 return LoadLibsecret() && LibsecretIsAvailable(); | 272 return LoadLibsecret() && LibsecretIsAvailable(); |
| 273 } | 273 } |
| 274 | 274 |
| 275 password_manager::PasswordStoreChangeList NativeBackendLibsecret::AddLogin( | 275 password_manager::PasswordStoreChangeList NativeBackendLibsecret::AddLogin( |
| 276 const PasswordForm& form) { | 276 const PasswordForm& form) { |
| 277 // Based on LoginDatabase::AddLogin(), we search for an existing match based | 277 // Based on LoginDatabase::AddLogin(), we search for an existing match based |
| 278 // on origin_url, username_element, username_value, password_element, submit | 278 // on origin_url, username_element, username_value, password_element, submit |
| 279 // element, and signon_realm first, remove that, and then add the new entry. | 279 // element, and signon_realm first, remove that, and then add the new entry. |
| 280 // We'd add the new one first, and then delete the original, but then the | 280 // We'd add the new one first, and then delete the original, but then the |
| 281 // delete might actually delete the newly-added entry! | 281 // delete might actually delete the newly-added entry! |
| 282 ScopedVector<autofill::PasswordForm> forms; | 282 ScopedVector<autofill::PasswordForm> forms = |
| 283 AddUpdateLoginSearch(form, SEARCH_USE_SUBMIT, &forms); | 283 AddUpdateLoginSearch(form, SEARCH_USE_SUBMIT); |
| 284 password_manager::PasswordStoreChangeList changes; | 284 password_manager::PasswordStoreChangeList changes; |
| 285 if (forms.size() > 0) { | 285 if (forms.size() > 0) { |
| 286 if (forms.size() > 1) { | 286 if (forms.size() > 1) { |
| 287 VLOG(1) << "Adding login when there are " << forms.size() | 287 VLOG(1) << "Adding login when there are " << forms.size() |
| 288 << " matching logins already! Will replace only the first."; | 288 << " matching logins already! Will replace only the first."; |
| 289 } | 289 } |
| 290 | 290 |
| 291 if (RemoveLogin(*forms[0])) { | 291 if (RemoveLogin(*forms[0])) { |
| 292 changes.push_back(password_manager::PasswordStoreChange( | 292 changes.push_back(password_manager::PasswordStoreChange( |
| 293 password_manager::PasswordStoreChange::REMOVE, *forms[0])); | 293 password_manager::PasswordStoreChange::REMOVE, *forms[0])); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 305 password_manager::PasswordStoreChangeList* changes) { | 305 password_manager::PasswordStoreChangeList* changes) { |
| 306 // Based on LoginDatabase::UpdateLogin(), we search for forms to update by | 306 // Based on LoginDatabase::UpdateLogin(), we search for forms to update by |
| 307 // origin_url, username_element, username_value, password_element, and | 307 // origin_url, username_element, username_value, password_element, and |
| 308 // signon_realm. We then compare the result to the updated form. If they | 308 // signon_realm. We then compare the result to the updated form. If they |
| 309 // differ in any of the mutable fields, then we remove the original, and | 309 // differ in any of the mutable fields, then we remove the original, and |
| 310 // then add the new entry. We'd add the new one first, and then delete the | 310 // then add the new entry. We'd add the new one first, and then delete the |
| 311 // original, but then the delete might actually delete the newly-added entry! | 311 // original, but then the delete might actually delete the newly-added entry! |
| 312 DCHECK(changes); | 312 DCHECK(changes); |
| 313 changes->clear(); | 313 changes->clear(); |
| 314 | 314 |
| 315 ScopedVector<autofill::PasswordForm> forms; | 315 ScopedVector<autofill::PasswordForm> forms = |
| 316 AddUpdateLoginSearch(form, SEARCH_IGNORE_SUBMIT, &forms); | 316 AddUpdateLoginSearch(form, SEARCH_IGNORE_SUBMIT); |
| 317 | 317 |
| 318 bool removed = false; | 318 bool removed = false; |
| 319 for (size_t i = 0; i < forms.size(); ++i) { | 319 for (size_t i = 0; i < forms.size(); ++i) { |
| 320 if (*forms[i] != form) { | 320 if (*forms[i] != form) { |
| 321 RemoveLogin(*forms[i]); | 321 RemoveLogin(*forms[i]); |
| 322 removed = true; | 322 removed = true; |
| 323 } | 323 } |
| 324 } | 324 } |
| 325 if (!removed) | 325 if (!removed) |
| 326 return true; | 326 return true; |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 367 password_manager::PasswordStoreChangeList* changes) { | 367 password_manager::PasswordStoreChangeList* changes) { |
| 368 return RemoveLoginsBetween(delete_begin, delete_end, SYNC_TIMESTAMP, changes); | 368 return RemoveLoginsBetween(delete_begin, delete_end, SYNC_TIMESTAMP, changes); |
| 369 } | 369 } |
| 370 | 370 |
| 371 bool NativeBackendLibsecret::GetLogins( | 371 bool NativeBackendLibsecret::GetLogins( |
| 372 const PasswordForm& form, | 372 const PasswordForm& form, |
| 373 ScopedVector<autofill::PasswordForm>* forms) { | 373 ScopedVector<autofill::PasswordForm>* forms) { |
| 374 return GetLoginsList(&form, ALL_LOGINS, forms); | 374 return GetLoginsList(&form, ALL_LOGINS, forms); |
| 375 } | 375 } |
| 376 | 376 |
| 377 void NativeBackendLibsecret::AddUpdateLoginSearch( | 377 ScopedVector<autofill::PasswordForm> |
| 378 NativeBackendLibsecret::AddUpdateLoginSearch( |
| 378 const autofill::PasswordForm& lookup_form, | 379 const autofill::PasswordForm& lookup_form, |
| 379 AddUpdateLoginSearchOptions options, | 380 AddUpdateLoginSearchOptions options) { |
| 380 ScopedVector<autofill::PasswordForm>* forms) { | |
| 381 LibsecretAttributesBuilder attrs; | 381 LibsecretAttributesBuilder attrs; |
| 382 attrs.Append("origin_url", lookup_form.origin.spec()); | 382 attrs.Append("origin_url", lookup_form.origin.spec()); |
| 383 attrs.Append("username_element", UTF16ToUTF8(lookup_form.username_element)); | 383 attrs.Append("username_element", UTF16ToUTF8(lookup_form.username_element)); |
| 384 attrs.Append("username_value", UTF16ToUTF8(lookup_form.username_value)); | 384 attrs.Append("username_value", UTF16ToUTF8(lookup_form.username_value)); |
| 385 attrs.Append("password_element", UTF16ToUTF8(lookup_form.password_element)); | 385 attrs.Append("password_element", UTF16ToUTF8(lookup_form.password_element)); |
| 386 if (options == SEARCH_USE_SUBMIT) | 386 if (options == SEARCH_USE_SUBMIT) |
| 387 attrs.Append("submit_element", UTF16ToUTF8(lookup_form.submit_element)); | 387 attrs.Append("submit_element", UTF16ToUTF8(lookup_form.submit_element)); |
| 388 attrs.Append("signon_realm", lookup_form.signon_realm); | 388 attrs.Append("signon_realm", lookup_form.signon_realm); |
| 389 attrs.Append("application", app_string_); | 389 attrs.Append("application", app_string_); |
| 390 | 390 |
| 391 GError* error = nullptr; | 391 GError* error = nullptr; |
| 392 GList* found = secret_service_search_sync(nullptr, // default secret service | 392 GList* found = secret_service_search_sync(nullptr, // default secret service |
| 393 &kLibsecretSchema, attrs.Get(), | 393 &kLibsecretSchema, attrs.Get(), |
| 394 SECRET_SEARCH_ALL, | 394 SECRET_SEARCH_ALL, |
| 395 nullptr, // no cancellable ojbect | 395 nullptr, // no cancellable ojbect |
| 396 &error); | 396 &error); |
| 397 if (error) { | 397 if (error) { |
| 398 VLOG(1) << "Unable to get logins " << error->message; | 398 VLOG(1) << "Unable to get logins " << error->message; |
| 399 g_error_free(error); | 399 g_error_free(error); |
| 400 if (found) | 400 if (found) |
| 401 g_list_free(found); | 401 g_list_free(found); |
| 402 return; | 402 return ScopedVector<autofill::PasswordForm>(); |
| 403 } | 403 } |
| 404 | 404 |
| 405 ConvertFormList(found, &lookup_form, forms); | 405 return ConvertFormList(found, &lookup_form); |
| 406 } | 406 } |
| 407 | 407 |
| 408 bool NativeBackendLibsecret::RawAddLogin(const PasswordForm& form) { | 408 bool NativeBackendLibsecret::RawAddLogin(const PasswordForm& form) { |
| 409 int64 date_created = form.date_created.ToInternalValue(); | 409 int64 date_created = form.date_created.ToInternalValue(); |
| 410 // If we are asked to save a password with 0 date, use the current time. | 410 // If we are asked to save a password with 0 date, use the current time. |
| 411 // We don't want to actually save passwords as though on January 1, 1601. | 411 // We don't want to actually save passwords as though on January 1, 1601. |
| 412 if (!date_created) | 412 if (!date_created) |
| 413 date_created = base::Time::Now().ToInternalValue(); | 413 date_created = base::Time::Now().ToInternalValue(); |
| 414 int64 date_synced = form.date_synced.ToInternalValue(); | 414 int64 date_synced = form.date_synced.ToInternalValue(); |
| 415 GError* error = nullptr; | 415 GError* error = nullptr; |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 456 | 456 |
| 457 bool NativeBackendLibsecret::GetBlacklistLogins( | 457 bool NativeBackendLibsecret::GetBlacklistLogins( |
| 458 ScopedVector<autofill::PasswordForm>* forms) { | 458 ScopedVector<autofill::PasswordForm>* forms) { |
| 459 return GetLoginsList(nullptr, BLACKLISTED_LOGINS, forms); | 459 return GetLoginsList(nullptr, BLACKLISTED_LOGINS, forms); |
| 460 } | 460 } |
| 461 | 461 |
| 462 bool NativeBackendLibsecret::GetLoginsList( | 462 bool NativeBackendLibsecret::GetLoginsList( |
| 463 const PasswordForm* lookup_form, | 463 const PasswordForm* lookup_form, |
| 464 GetLoginsListOptions options, | 464 GetLoginsListOptions options, |
| 465 ScopedVector<autofill::PasswordForm>* forms) { | 465 ScopedVector<autofill::PasswordForm>* forms) { |
| 466 forms->clear(); |
| 466 LibsecretAttributesBuilder attrs; | 467 LibsecretAttributesBuilder attrs; |
| 467 attrs.Append("application", app_string_); | 468 attrs.Append("application", app_string_); |
| 468 if (options != ALL_LOGINS) | 469 if (options != ALL_LOGINS) |
| 469 attrs.Append("blacklisted_by_user", options == BLACKLISTED_LOGINS); | 470 attrs.Append("blacklisted_by_user", options == BLACKLISTED_LOGINS); |
| 470 if (lookup_form && | 471 if (lookup_form && |
| 471 !password_manager::ShouldPSLDomainMatchingApply( | 472 !password_manager::ShouldPSLDomainMatchingApply( |
| 472 password_manager::GetRegistryControlledDomain( | 473 password_manager::GetRegistryControlledDomain( |
| 473 GURL(lookup_form->signon_realm)))) | 474 GURL(lookup_form->signon_realm)))) |
| 474 attrs.Append("signon_realm", lookup_form->signon_realm); | 475 attrs.Append("signon_realm", lookup_form->signon_realm); |
| 475 | 476 |
| 476 GError* error = nullptr; | 477 GError* error = nullptr; |
| 477 GList* found = secret_service_search_sync(nullptr, // default secret service | 478 GList* found = secret_service_search_sync(nullptr, // default secret service |
| 478 &kLibsecretSchema, attrs.Get(), | 479 &kLibsecretSchema, attrs.Get(), |
| 479 SECRET_SEARCH_ALL, | 480 SECRET_SEARCH_ALL, |
| 480 nullptr, // no cancellable ojbect | 481 nullptr, // no cancellable ojbect |
| 481 &error); | 482 &error); |
| 482 if (error) { | 483 if (error) { |
| 483 VLOG(1) << "Unable to get logins " << error->message; | 484 VLOG(1) << "Unable to get logins " << error->message; |
| 484 g_error_free(error); | 485 g_error_free(error); |
| 485 if (found) | 486 if (found) |
| 486 g_list_free(found); | 487 g_list_free(found); |
| 487 return false; | 488 return false; |
| 488 } | 489 } |
| 489 | 490 |
| 490 return ConvertFormList(found, lookup_form, forms); | 491 *forms = ConvertFormList(found, lookup_form); |
| 491 } | 492 return true; |
| 492 | |
| 493 bool NativeBackendLibsecret::GetAllLogins( | |
| 494 ScopedVector<autofill::PasswordForm>* forms) { | |
| 495 return GetLoginsList(nullptr, ALL_LOGINS, forms); | |
| 496 } | 493 } |
| 497 | 494 |
| 498 bool NativeBackendLibsecret::GetLoginsBetween( | 495 bool NativeBackendLibsecret::GetLoginsBetween( |
| 499 base::Time get_begin, | 496 base::Time get_begin, |
| 500 base::Time get_end, | 497 base::Time get_end, |
| 501 TimestampToCompare date_to_compare, | 498 TimestampToCompare date_to_compare, |
| 502 ScopedVector<autofill::PasswordForm>* forms) { | 499 ScopedVector<autofill::PasswordForm>* forms) { |
| 503 ScopedVector<autofill::PasswordForm> all_forms; | 500 ScopedVector<autofill::PasswordForm> all_forms; |
| 504 if (!GetAllLogins(&all_forms)) | 501 if (!GetLoginsList(nullptr, ALL_LOGINS, forms)) |
| 505 return false; | 502 return false; |
| 506 | 503 |
| 507 base::Time autofill::PasswordForm::*date_member = | 504 base::Time autofill::PasswordForm::*date_member = |
| 508 date_to_compare == CREATION_TIMESTAMP | 505 date_to_compare == CREATION_TIMESTAMP |
| 509 ? &autofill::PasswordForm::date_created | 506 ? &autofill::PasswordForm::date_created |
| 510 : &autofill::PasswordForm::date_synced; | 507 : &autofill::PasswordForm::date_synced; |
| 511 for (auto& saved_form : all_forms) { | 508 for (auto& saved_form : all_forms) { |
| 512 if (get_begin <= saved_form->*date_member && | 509 if (get_begin <= saved_form->*date_member && |
| 513 (get_end.is_null() || saved_form->*date_member < get_end)) { | 510 (get_end.is_null() || saved_form->*date_member < get_end)) { |
| 514 forms->push_back(saved_form); | 511 forms->push_back(saved_form); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 535 if (RemoveLogin(*forms[i])) { | 532 if (RemoveLogin(*forms[i])) { |
| 536 changes->push_back(password_manager::PasswordStoreChange( | 533 changes->push_back(password_manager::PasswordStoreChange( |
| 537 password_manager::PasswordStoreChange::REMOVE, *forms[i])); | 534 password_manager::PasswordStoreChange::REMOVE, *forms[i])); |
| 538 } else { | 535 } else { |
| 539 ok = false; | 536 ok = false; |
| 540 } | 537 } |
| 541 } | 538 } |
| 542 return ok; | 539 return ok; |
| 543 } | 540 } |
| 544 | 541 |
| 545 bool NativeBackendLibsecret::ConvertFormList( | 542 ScopedVector<autofill::PasswordForm> NativeBackendLibsecret::ConvertFormList( |
| 546 GList* found, | 543 GList* found, |
| 547 const PasswordForm* lookup_form, | 544 const PasswordForm* lookup_form) { |
| 548 ScopedVector<autofill::PasswordForm>* forms) { | 545 ScopedVector<autofill::PasswordForm> forms; |
| 549 password_manager::PSLDomainMatchMetric psl_domain_match_metric = | 546 password_manager::PSLDomainMatchMetric psl_domain_match_metric = |
| 550 password_manager::PSL_DOMAIN_MATCH_NONE; | 547 password_manager::PSL_DOMAIN_MATCH_NONE; |
| 551 GError* error = nullptr; | 548 GError* error = nullptr; |
| 552 for (GList* element = g_list_first(found); element != nullptr; | 549 for (GList* element = g_list_first(found); element != nullptr; |
| 553 element = g_list_next(element)) { | 550 element = g_list_next(element)) { |
| 554 SecretItem* secretItem = static_cast<SecretItem*>(element->data); | 551 SecretItem* secretItem = static_cast<SecretItem*>(element->data); |
| 555 LibsecretLoader::secret_item_load_secret_sync(secretItem, nullptr, &error); | 552 LibsecretLoader::secret_item_load_secret_sync(secretItem, nullptr, &error); |
| 556 if (error) { | 553 if (error) { |
| 557 VLOG(1) << "Unable to load secret item" << error->message; | 554 VLOG(1) << "Unable to load secret item" << error->message; |
| 558 g_error_free(error); | 555 g_error_free(error); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 576 form->signon_realm = lookup_form->signon_realm; | 573 form->signon_realm = lookup_form->signon_realm; |
| 577 form->origin = lookup_form->origin; | 574 form->origin = lookup_form->origin; |
| 578 } | 575 } |
| 579 SecretValue* secretValue = secret_item_get_secret(secretItem); | 576 SecretValue* secretValue = secret_item_get_secret(secretItem); |
| 580 if (secretValue) { | 577 if (secretValue) { |
| 581 form->password_value = UTF8ToUTF16(secret_value_get_text(secretValue)); | 578 form->password_value = UTF8ToUTF16(secret_value_get_text(secretValue)); |
| 582 secret_value_unref(secretValue); | 579 secret_value_unref(secretValue); |
| 583 } else { | 580 } else { |
| 584 VLOG(1) << "Unable to access password from list element!"; | 581 VLOG(1) << "Unable to access password from list element!"; |
| 585 } | 582 } |
| 586 forms->push_back(form.release()); | 583 forms.push_back(form.release()); |
| 587 } else { | 584 } else { |
| 588 VLOG(1) << "Could not initialize PasswordForm from attributes!"; | 585 VLOG(1) << "Could not initialize PasswordForm from attributes!"; |
| 589 } | 586 } |
| 590 } | 587 } |
| 591 | 588 |
| 592 if (lookup_form) { | 589 if (lookup_form) { |
| 593 const GURL signon_realm(lookup_form->signon_realm); | 590 const GURL signon_realm(lookup_form->signon_realm); |
| 594 std::string registered_domain = | 591 std::string registered_domain = |
| 595 password_manager::GetRegistryControlledDomain(signon_realm); | 592 password_manager::GetRegistryControlledDomain(signon_realm); |
| 596 UMA_HISTOGRAM_ENUMERATION( | 593 UMA_HISTOGRAM_ENUMERATION( |
| 597 "PasswordManager.PslDomainMatchTriggering", | 594 "PasswordManager.PslDomainMatchTriggering", |
| 598 password_manager::ShouldPSLDomainMatchingApply(registered_domain) | 595 password_manager::ShouldPSLDomainMatchingApply(registered_domain) |
| 599 ? psl_domain_match_metric | 596 ? psl_domain_match_metric |
| 600 : password_manager::PSL_DOMAIN_MATCH_NOT_USED, | 597 : password_manager::PSL_DOMAIN_MATCH_NOT_USED, |
| 601 password_manager::PSL_DOMAIN_MATCH_COUNT); | 598 password_manager::PSL_DOMAIN_MATCH_COUNT); |
| 602 } | 599 } |
| 603 g_list_free(found); | 600 g_list_free(found); |
| 604 return true; | 601 return forms.Pass(); |
| 605 } | 602 } |
| 606 | 603 |
| 607 std::string NativeBackendLibsecret::GetProfileSpecificAppString( | 604 std::string NativeBackendLibsecret::GetProfileSpecificAppString( |
| 608 LocalProfileId id) { | 605 LocalProfileId id) { |
| 609 // Originally, the application string was always just "chrome" and used only | 606 // Originally, the application string was always just "chrome" and used only |
| 610 // so that we had *something* to search for since GNOME Keyring won't search | 607 // so that we had *something* to search for since GNOME Keyring won't search |
| 611 // for nothing. Now we use it to distinguish passwords for different profiles. | 608 // for nothing. Now we use it to distinguish passwords for different profiles. |
| 612 return base::StringPrintf("%s-%d", kLibsecretAppString, id); | 609 return base::StringPrintf("%s-%d", kLibsecretAppString, id); |
| 613 } | 610 } |
| OLD | NEW |