diff options
author | mdm@chromium.org <mdm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-06-04 22:21:13 +0000 |
---|---|---|
committer | mdm@chromium.org <mdm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-06-04 22:21:13 +0000 |
commit | e43cf994ac0b0840c6712346d8a8788c4a71574a (patch) | |
tree | 780031099e2da5b453a493a214ab0246908f08dc /chrome | |
parent | 66dc0bdb78955160e52004da17ebab021be64e0c (diff) | |
download | chromium_src-e43cf994ac0b0840c6712346d8a8788c4a71574a.zip chromium_src-e43cf994ac0b0840c6712346d8a8788c4a71574a.tar.gz chromium_src-e43cf994ac0b0840c6712346d8a8788c4a71574a.tar.bz2 |
Linux: bring GNOME Keyring and KWallet integration back into a compilable state. Still disabled, however.
BUG=12351,25404
TEST=both now seem to work correctly when enabled (but this CL does not enable them)
Review URL: http://codereview.chromium.org/2407001
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@48983 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
5 files changed, 532 insertions, 180 deletions
diff --git a/chrome/browser/password_manager/password_store.h b/chrome/browser/password_manager/password_store.h index b2e6ef0..14203fd 100644 --- a/chrome/browser/password_manager/password_store.h +++ b/chrome/browser/password_manager/password_store.h @@ -110,11 +110,12 @@ class PasswordStore : public base::RefCountedThreadSafe<PasswordStore> { virtual void UpdateLoginImpl(const webkit_glue::PasswordForm& form) = 0; // Synchronous implementation to remove the given login. virtual void RemoveLoginImpl(const webkit_glue::PasswordForm& form) = 0; + // Synchronous implementation to remove the given logins. + virtual void RemoveLoginsCreatedBetweenImpl(const base::Time& delete_begin, + const base::Time& delete_end) = 0; // Should find all PasswordForms with the same signon_realm. The results // will then be scored by the PasswordFormManager. Once they are found // (or not), the consumer should be notified. - virtual void RemoveLoginsCreatedBetweenImpl(const base::Time& delete_begin, - const base::Time& delete_end) = 0; virtual void GetLoginsImpl(GetLoginsRequest* request, const webkit_glue::PasswordForm& form) = 0; // Finds all non-blacklist PasswordForms, and notifies the consumer. diff --git a/chrome/browser/password_manager/password_store_gnome.cc b/chrome/browser/password_manager/password_store_gnome.cc index 93f3b6f..f57208d 100644 --- a/chrome/browser/password_manager/password_store_gnome.cc +++ b/chrome/browser/password_manager/password_store_gnome.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -10,10 +10,14 @@ #include "base/string_util.h" #include "base/task.h" #include "base/time.h" +#include "base/utf_string_conversions.h" using std::map; using std::string; using std::vector; +using webkit_glue::PasswordForm; + +#define GNOME_KEYRING_APPLICATION_CHROME "chrome" // Schema is analagous to the fields in PasswordForm. const GnomeKeyringPasswordSchema PasswordStoreGnome::kGnomeSchema = { @@ -30,11 +34,15 @@ const GnomeKeyringPasswordSchema PasswordStoreGnome::kGnomeSchema = { { "date_created", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING }, { "blacklisted_by_user", GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32 }, { "scheme", GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32 }, + // This field is always "chrome" so that we can search for it. + { "application", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING }, { NULL } } }; -PasswordStoreGnome::PasswordStoreGnome() { +PasswordStoreGnome::PasswordStoreGnome(LoginDatabase* login_db, + Profile* profile, + WebDataService* web_data_service) { } PasswordStoreGnome::~PasswordStoreGnome() { @@ -45,91 +53,222 @@ bool PasswordStoreGnome::Init() { } void PasswordStoreGnome::AddLoginImpl(const PasswordForm& form) { - AutoLock l(gnome_keyring_lock_); - GnomeKeyringResult result = gnome_keyring_store_password_sync( + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::DB)); + AddLoginHelper(form, base::Time::Now()); +} + +void PasswordStoreGnome::UpdateLoginImpl(const PasswordForm& form) { + // Based on LoginDatabase::UpdateLogin(), we search for forms to update by + // origin_url, username_element, username_value, password_element, and + // signon_realm. We then compare the result to the updated form. If they + // differ in any of the action, password_value, ssl_valid, or preferred + // fields, then we add a new login with those fields updated and only delete + // the original on success. + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::DB)); + GList* found = NULL; + // Search gnome keyring for matching passwords. + GnomeKeyringResult result = gnome_keyring_find_itemsv_sync( + GNOME_KEYRING_ITEM_GENERIC_SECRET, + &found, + "origin_url", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING, + form.origin.spec().c_str(), + "username_element", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING, + UTF16ToUTF8(form.username_element).c_str(), + "username_value", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING, + UTF16ToUTF8(form.username_value).c_str(), + "password_element", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING, + UTF16ToUTF8(form.password_element).c_str(), + "signon_realm", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING, + form.signon_realm.c_str(), + "application", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING, + GNOME_KEYRING_APPLICATION_CHROME, + NULL); + vector<PasswordForm*> forms; + if (result == GNOME_KEYRING_RESULT_OK) { + FillFormVector(found, &forms); + for (size_t i = 0; i < forms.size(); ++i) { + if (forms[i]->action != form.action || + forms[i]->password_value != form.password_value || + forms[i]->ssl_valid != form.ssl_valid || + forms[i]->preferred != form.preferred) { + PasswordForm updated = *forms[i]; + updated.action = form.action; + updated.password_value = form.password_value; + updated.ssl_valid = form.ssl_valid; + updated.preferred = form.preferred; + if (AddLoginHelper(updated, updated.date_created)) + RemoveLoginImpl(*forms[i]); + } + delete forms[i]; + } + } else { + LOG(ERROR) << "Keyring find failed: " + << gnome_keyring_result_to_message(result); + } +} + +void PasswordStoreGnome::RemoveLoginImpl(const PasswordForm& form) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::DB)); + // We find forms using the same fields as LoginDatabase::RemoveLogin(). + GnomeKeyringResult result = gnome_keyring_delete_password_sync( &kGnomeSchema, - NULL, // Default keyring. - // TODO(johnmaguire@google.com): Localise this. - "Form password stored by Chrome", - WideToASCII(form.password_value).c_str(), "origin_url", form.origin.spec().c_str(), "action_url", form.action.spec().c_str(), - "username_element", form.username_element.c_str(), - "username_value", form.username_value.c_str(), - "password_element", form.password_element.c_str(), - "submit_element", form.submit_element.c_str(), + "username_element", UTF16ToUTF8(form.username_element).c_str(), + "username_value", UTF16ToUTF8(form.username_value).c_str(), + "password_element", UTF16ToUTF8(form.password_element).c_str(), + "submit_element", UTF16ToUTF8(form.submit_element).c_str(), "signon_realm", form.signon_realm.c_str(), - "ssl_valid", form.ssl_valid, - "preferred", form.preferred, - "date_created", Int64ToString(base::Time::Now().ToTimeT()).c_str(), - "blacklisted_by_user", form.blacklisted_by_user, - "scheme", form.scheme, NULL); - if (result != GNOME_KEYRING_RESULT_OK) { - LOG(ERROR) << "Keyring save failed: " + LOG(ERROR) << "Keyring delete failed: " << gnome_keyring_result_to_message(result); } } -void PasswordStoreGnome::UpdateLoginImpl(const PasswordForm& form) { - AddLoginImpl(form); // Add & Update are the same in gnome keyring. +void PasswordStoreGnome::RemoveLoginsCreatedBetweenImpl( + const base::Time& delete_begin, + const base::Time& delete_end) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::DB)); + GList* found = NULL; + // Search GNOME keyring for all passwords, then delete the ones in the range. + // We need to search for something, otherwise we get no results - so we search + // for the fixed application string. + GnomeKeyringResult result = gnome_keyring_find_itemsv_sync( + GNOME_KEYRING_ITEM_GENERIC_SECRET, + &found, + "application", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING, + GNOME_KEYRING_APPLICATION_CHROME, + NULL); + if (result == GNOME_KEYRING_RESULT_OK) { + // We could walk the list and delete items as we find them, but it is much + // easier to build the vector and use RemoveLoginImpl() to delete them. + vector<PasswordForm*> forms; + FillFormVector(found, &forms); + for (size_t i = 0; i < forms.size(); ++i) { + if (delete_begin <= forms[i]->date_created && + (delete_end.is_null() || forms[i]->date_created < delete_end)) { + RemoveLoginImpl(*forms[i]); + } + delete forms[i]; + } + } else if (result != GNOME_KEYRING_RESULT_NO_MATCH) { + LOG(ERROR) << "Keyring find failed: " + << gnome_keyring_result_to_message(result); + } } -void PasswordStoreGnome::RemoveLoginImpl(const PasswordForm& form) { - AutoLock l(gnome_keyring_lock_); - GnomeKeyringResult result = gnome_keyring_delete_password_sync( +void PasswordStoreGnome::GetLoginsImpl(GetLoginsRequest* request, + const PasswordForm& form) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::DB)); + GList* found = NULL; + // Search gnome keyring for matching passwords. + GnomeKeyringResult result = gnome_keyring_find_itemsv_sync( + GNOME_KEYRING_ITEM_GENERIC_SECRET, + &found, + "signon_realm", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING, + form.signon_realm.c_str(), + "application", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING, + GNOME_KEYRING_APPLICATION_CHROME, + NULL); + vector<PasswordForm*> forms; + if (result == GNOME_KEYRING_RESULT_OK) { + FillFormVector(found, &forms); + } else if (result != GNOME_KEYRING_RESULT_NO_MATCH) { + LOG(ERROR) << "Keyring find failed: " + << gnome_keyring_result_to_message(result); + } + NotifyConsumer(request, forms); +} + +void PasswordStoreGnome::GetAutofillableLoginsImpl( + GetLoginsRequest* request) { + std::vector<PasswordForm*> forms; + FillAutofillableLogins(&forms); + NotifyConsumer(request, forms); +} + +void PasswordStoreGnome::GetBlacklistLoginsImpl( + GetLoginsRequest* request) { + std::vector<PasswordForm*> forms; + FillBlacklistLogins(&forms); + NotifyConsumer(request, forms); +} + +bool PasswordStoreGnome::FillAutofillableLogins( + std::vector<PasswordForm*>* forms) { + return FillSomeLogins(true, forms); +} + +bool PasswordStoreGnome::FillBlacklistLogins( + std::vector<PasswordForm*>* forms) { + return FillSomeLogins(false, forms); +} + +bool PasswordStoreGnome::AddLoginHelper(const PasswordForm& form, + const base::Time& date_created) { + GnomeKeyringResult result = gnome_keyring_store_password_sync( &kGnomeSchema, + NULL, // Default keyring. + form.origin.spec().c_str(), // Display name. + UTF16ToUTF8(form.password_value).c_str(), "origin_url", form.origin.spec().c_str(), "action_url", form.action.spec().c_str(), - "username_element", form.username_element.c_str(), - "username_value", form.username_value.c_str(), - "password_element", form.password_element.c_str(), - "submit_element", form.submit_element.c_str(), + "username_element", UTF16ToUTF8(form.username_element).c_str(), + "username_value", UTF16ToUTF8(form.username_value).c_str(), + "password_element", UTF16ToUTF8(form.password_element).c_str(), + "submit_element", UTF16ToUTF8(form.submit_element).c_str(), "signon_realm", form.signon_realm.c_str(), "ssl_valid", form.ssl_valid, "preferred", form.preferred, - "date_created", Int64ToString(form.date_created.ToTimeT()).c_str(), + "date_created", Int64ToString(date_created.ToTimeT()).c_str(), "blacklisted_by_user", form.blacklisted_by_user, "scheme", form.scheme, + "application", GNOME_KEYRING_APPLICATION_CHROME, NULL); + if (result != GNOME_KEYRING_RESULT_OK) { - LOG(ERROR) << "Keyring delete failed: " + LOG(ERROR) << "Keyring save failed: " << gnome_keyring_result_to_message(result); + return false; } + return true; } -void PasswordStoreGnome::GetLoginsImpl(GetLoginsRequest* request) { - AutoLock l(gnome_keyring_lock_); +bool PasswordStoreGnome::FillSomeLogins( + bool autofillable, + std::vector<PasswordForm*>* forms) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::DB)); GList* found = NULL; + uint32_t blacklisted_by_user = !autofillable; // Search gnome keyring for matching passwords. GnomeKeyringResult result = gnome_keyring_find_itemsv_sync( GNOME_KEYRING_ITEM_GENERIC_SECRET, &found, - "signon_realm", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING, - request->form.signon_realm.c_str(), + "blacklisted_by_user", GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32, + blacklisted_by_user, + "application", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING, + GNOME_KEYRING_APPLICATION_CHROME, NULL); - vector<PasswordForm*> forms; - if (result == GNOME_KEYRING_RESULT_NO_MATCH) { - NotifyConsumer(request, forms); - return; - } else if (result != GNOME_KEYRING_RESULT_OK) { + if (result == GNOME_KEYRING_RESULT_OK) { + FillFormVector(found, forms); + } else if (result != GNOME_KEYRING_RESULT_NO_MATCH) { LOG(ERROR) << "Keyring find failed: " << gnome_keyring_result_to_message(result); - NotifyConsumer(request, forms); - return; + return false; } + return true; +} - // Parse all the results from the returned GList into a - // vector<PasswordForm*>. PasswordForms are allocated on the heap. These - // will be deleted by the consumer. +void PasswordStoreGnome::FillFormVector(GList* found, + std::vector<PasswordForm*>* forms) { GList* element = g_list_first(found); while (element != NULL) { GnomeKeyringFound* data = static_cast<GnomeKeyringFound*>(element->data); char* password = data->secret; GnomeKeyringAttributeList* attributes = data->attributes; - // Read the string & int attributes into the appropriate map. + // Read the string and int attributes into the appropriate map. map<string, string> string_attribute_map; map<string, uint32> uint_attribute_map; for (unsigned int i = 0; i < attributes->len; ++i) { @@ -147,31 +286,30 @@ void PasswordStoreGnome::GetLoginsImpl(GetLoginsRequest* request) { form->origin = GURL(string_attribute_map["origin_url"]); form->action = GURL(string_attribute_map["action_url"]); form->username_element = - ASCIIToWide(string(string_attribute_map["username_element"])); + UTF8ToUTF16(string(string_attribute_map["username_element"])); form->username_value = - ASCIIToWide(string(string_attribute_map["username_value"])); + UTF8ToUTF16(string(string_attribute_map["username_value"])); form->password_element = - ASCIIToWide(string(string_attribute_map["password_element"])); - form->password_value = ASCIIToWide(string(password)); + UTF8ToUTF16(string(string_attribute_map["password_element"])); + form->password_value = UTF8ToUTF16(string(password)); form->submit_element = - ASCIIToWide(string(string_attribute_map["submit_element"])); - form->signon_realm = uint_attribute_map["signon_realm"]; + UTF8ToUTF16(string(string_attribute_map["submit_element"])); + form->signon_realm = string_attribute_map["signon_realm"]; form->ssl_valid = uint_attribute_map["ssl_valid"]; form->preferred = uint_attribute_map["preferred"]; string date = string_attribute_map["date_created"]; int64 date_created = 0; - DCHECK(StringToInt64(date, &date_created) && date_created != 0); + bool date_ok = StringToInt64(date, &date_created); + DCHECK(date_ok); + DCHECK(date_created != 0); form->date_created = base::Time::FromTimeT(date_created); form->blacklisted_by_user = uint_attribute_map["blacklisted_by_user"]; - form->scheme = - static_cast<PasswordForm::Scheme>(uint_attribute_map["scheme"]); + form->scheme = static_cast<PasswordForm::Scheme>( + uint_attribute_map["scheme"]); - forms.push_back(form); + forms->push_back(form); element = g_list_next(element); } gnome_keyring_found_list_free(found); - found = NULL; - - NotifyConsumer(request, forms); } diff --git a/chrome/browser/password_manager/password_store_gnome.h b/chrome/browser/password_manager/password_store_gnome.h index f448ad1..8927ba3 100644 --- a/chrome/browser/password_manager/password_store_gnome.h +++ b/chrome/browser/password_manager/password_store_gnome.h @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -9,31 +9,59 @@ extern "C" { #include <gnome-keyring.h> } +#include <vector> + #include "base/lock.h" +#include "chrome/browser/password_manager/login_database.h" #include "chrome/browser/password_manager/password_store.h" +#include "chrome/browser/profile.h" +#include "chrome/browser/webdata/web_data_service.h" class Profile; class Task; -// PasswordStore implementation using Gnome Keyring. +// PasswordStore implementation using GNOME Keyring. class PasswordStoreGnome : public PasswordStore { public: - PasswordStoreGnome(); + PasswordStoreGnome(LoginDatabase* login_db, + Profile* profile, + WebDataService* web_data_service); virtual bool Init(); private: virtual ~PasswordStoreGnome(); - void AddLoginImpl(const PasswordForm& form); - void UpdateLoginImpl(const PasswordForm& form); - void RemoveLoginImpl(const PasswordForm& form); - void GetLoginsImpl(GetLoginsRequest* request); + // Implements PasswordStore interface. + virtual void AddLoginImpl(const webkit_glue::PasswordForm& form); + virtual void UpdateLoginImpl(const webkit_glue::PasswordForm& form); + virtual void RemoveLoginImpl(const webkit_glue::PasswordForm& form); + virtual void RemoveLoginsCreatedBetweenImpl(const base::Time& delete_begin, + const base::Time& delete_end); + virtual void GetLoginsImpl(GetLoginsRequest* request, + const webkit_glue::PasswordForm& form); + virtual void GetAutofillableLoginsImpl(GetLoginsRequest* request); + virtual void GetBlacklistLoginsImpl(GetLoginsRequest* request); + virtual bool FillAutofillableLogins( + std::vector<webkit_glue::PasswordForm*>* forms); + virtual bool FillBlacklistLogins( + std::vector<webkit_glue::PasswordForm*>* forms); - static const GnomeKeyringPasswordSchema kGnomeSchema; + // Helper for AddLoginImpl() and UpdateLoginImpl() with a success status. + bool AddLoginHelper(const webkit_glue::PasswordForm& form, + const base::Time& date_created); + + // Helper for FillAutofillableLogins() and FillBlacklistLogins(). + bool FillSomeLogins(bool autofillable, + std::vector<webkit_glue::PasswordForm*>* forms); - // Mutex for all interactions with Gnome Keyring. - Lock gnome_keyring_lock_; + // Parse all the results from the given GList into a + // vector<PasswordForm*>, and free the GList. PasswordForms are + // allocated on the heap, and should be deleted by the consumer. + void FillFormVector(GList* found, + std::vector<webkit_glue::PasswordForm*>* forms); + + static const GnomeKeyringPasswordSchema kGnomeSchema; DISALLOW_COPY_AND_ASSIGN(PasswordStoreGnome); }; diff --git a/chrome/browser/password_manager/password_store_kwallet.cc b/chrome/browser/password_manager/password_store_kwallet.cc index 1c50e3e..26f0ab9 100644 --- a/chrome/browser/password_manager/password_store_kwallet.cc +++ b/chrome/browser/password_manager/password_store_kwallet.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -9,12 +9,16 @@ #include "base/logging.h" #include "base/md5.h" #include "base/pickle.h" +#include "base/stl_util-inl.h" #include "base/string_util.h" #include "base/task.h" using std::string; using std::vector; +using webkit_glue::PasswordForm; +// We could localize these strings, but then changing your locale would cause +// you to lose access to all your stored passwords. Maybe best not to do that. const char* PasswordStoreKWallet::kAppId = "Chrome"; const char* PasswordStoreKWallet::kKWalletFolder = "Chrome Form Data"; @@ -25,7 +29,9 @@ const char* PasswordStoreKWallet::kKLauncherServiceName = "org.kde.klauncher"; const char* PasswordStoreKWallet::kKLauncherPath = "/KLauncher"; const char* PasswordStoreKWallet::kKLauncherInterface = "org.kde.KLauncher"; -PasswordStoreKWallet::PasswordStoreKWallet() +PasswordStoreKWallet::PasswordStoreKWallet(LoginDatabase* login_db, + Profile* profile, + WebDataService* web_data_service) : error_(NULL), connection_(NULL), proxy_(NULL) { @@ -38,13 +44,6 @@ PasswordStoreKWallet::~PasswordStoreKWallet() { } bool PasswordStoreKWallet::Init() { - thread_.reset(new base::Thread("Chrome_KeyringThread")); - - if (!thread_->Start()) { - thread_.reset(NULL); - return false; - } - // Initialize threading in dbus-glib - it should be fine for // dbus_g_thread_init to be called multiple times. if (!g_thread_supported()) @@ -56,8 +55,11 @@ bool PasswordStoreKWallet::Init() { if (CheckError()) return false; - if (!StartKWalletd()) return false; - if (!InitWallet()) return false; + if (!InitWallet()) { + // kwalletd may not be running. Try to start it and try again. + if (!StartKWalletd() || !InitWallet()) + return false; + } return true; } @@ -134,11 +136,12 @@ void PasswordStoreKWallet::AddLoginImpl(const PasswordForm& form) { return; PasswordFormList forms; - GetLoginsList(&forms, form, wallet_handle); + GetLoginsList(&forms, form.signon_realm, wallet_handle); - forms.push_back(const_cast<PasswordForm*>(&form)); + forms.push_back(new PasswordForm(form)); + SetLoginsList(forms, form.signon_realm, wallet_handle); - SetLoginsList(forms, form, wallet_handle); + STLDeleteElements(&forms); } void PasswordStoreKWallet::UpdateLoginImpl(const PasswordForm& form) { @@ -148,16 +151,16 @@ void PasswordStoreKWallet::UpdateLoginImpl(const PasswordForm& form) { return; PasswordFormList forms; - GetLoginsList(&forms, form, wallet_handle); + GetLoginsList(&forms, form.signon_realm, wallet_handle); - for (uint i = 0; i < forms.size(); ++i) { - if (CompareForms(form, *forms[i])) { - forms.erase(forms.begin() + i); - forms.insert(forms.begin() + i, const_cast<PasswordForm*>(&form)); - } + for (size_t i = 0; i < forms.size(); ++i) { + if (CompareForms(form, *forms[i], true)) + *forms[i] = form; } - SetLoginsList(forms, form, wallet_handle); + SetLoginsList(forms, form.signon_realm, wallet_handle); + + STLDeleteElements(&forms); } void PasswordStoreKWallet::RemoveLoginImpl(const PasswordForm& form) { @@ -166,57 +169,126 @@ void PasswordStoreKWallet::RemoveLoginImpl(const PasswordForm& form) { if (wallet_handle == kInvalidKWalletHandle) return; - PasswordFormList forms; - GetLoginsList(&forms, form, wallet_handle); + PasswordFormList all_forms; + GetLoginsList(&all_forms, form.signon_realm, wallet_handle); - for (uint i = 0; i < forms.size(); ++i) { - if (CompareForms(form, *forms[i])) { - forms.erase(forms.begin() + i); - --i; - } + PasswordFormList kept_forms; + kept_forms.reserve(all_forms.size()); + for (size_t i = 0; i < all_forms.size(); ++i) { + if (CompareForms(form, *all_forms[i], false)) + delete all_forms[i]; + else + kept_forms.push_back(all_forms[i]); } - if (forms.empty()) { - // No items left? Remove the entry from the wallet. - int ret = 0; - dbus_g_proxy_call(proxy_, "removeEntry", &error_, - G_TYPE_INT, wallet_handle, // handle - G_TYPE_STRING, kKWalletFolder, // folder - G_TYPE_STRING, form.signon_realm.c_str(), // key - G_TYPE_STRING, kAppId, // appid + // Update the entry in the wallet. + SetLoginsList(kept_forms, form.signon_realm, wallet_handle); + STLDeleteElements(&kept_forms); +} + +void PasswordStoreKWallet::RemoveLoginsCreatedBetweenImpl( + const base::Time& delete_begin, + const base::Time& delete_end) { + AutoLock l(kwallet_lock_); + int wallet_handle = WalletHandle(); + if (wallet_handle == kInvalidKWalletHandle) + return; + + // We could probably also use readEntryList here. + char** realm_list = NULL; + dbus_g_proxy_call(proxy_, "entryList", &error_, + G_TYPE_INT, wallet_handle, // handle + G_TYPE_STRING, kKWalletFolder, // folder + G_TYPE_STRING, kAppId, // appid + G_TYPE_INVALID, + G_TYPE_STRV, &realm_list, + G_TYPE_INVALID); + if (CheckError()) + return; + + for (char** realm = realm_list; *realm; ++realm) { + GArray* byte_array = NULL; + dbus_g_proxy_call(proxy_, "readEntry", &error_, + G_TYPE_INT, wallet_handle, // handle + G_TYPE_STRING, kKWalletFolder, // folder + G_TYPE_STRING, *realm, // key + G_TYPE_STRING, kAppId, // appid G_TYPE_INVALID, - G_TYPE_INT, &ret, + DBUS_TYPE_G_UCHAR_ARRAY, &byte_array, G_TYPE_INVALID); - CheckError(); - if (ret) - LOG(ERROR) << "Bad return code " << ret << " from kwallet removeEntry"; - } else { - // Otherwise update the entry in the wallet. - SetLoginsList(forms, form, wallet_handle); + + if (CheckError() || !byte_array || !byte_array->len) + continue; + + string signon_realm(*realm); + Pickle pickle(byte_array->data, byte_array->len); + PasswordFormList all_forms; + DeserializeValue(signon_realm, pickle, &all_forms); + g_array_free(byte_array, true); + + PasswordFormList kept_forms; + kept_forms.reserve(all_forms.size()); + for (size_t i = 0; i < all_forms.size(); ++i) { + if (delete_begin <= all_forms[i]->date_created && + (delete_end.is_null() || all_forms[i]->date_created < delete_end)) { + delete all_forms[i]; + } else { + kept_forms.push_back(all_forms[i]); + } + } + + SetLoginsList(kept_forms, signon_realm, wallet_handle); + STLDeleteElements(&kept_forms); } + g_strfreev(realm_list); } -void PasswordStoreKWallet::GetLoginsImpl(GetLoginsRequest* request) { +void PasswordStoreKWallet::GetLoginsImpl(GetLoginsRequest* request, + const PasswordForm& form) { PasswordFormList forms; AutoLock l(kwallet_lock_); int wallet_handle = WalletHandle(); if (wallet_handle != kInvalidKWalletHandle) - GetLoginsList(&forms, request->form, wallet_handle); + GetLoginsList(&forms, form.signon_realm, wallet_handle); NotifyConsumer(request, forms); } +void PasswordStoreKWallet::GetAutofillableLoginsImpl( + GetLoginsRequest* request) { + std::vector<PasswordForm*> forms; + FillAutofillableLogins(&forms); + NotifyConsumer(request, forms); +} + +void PasswordStoreKWallet::GetBlacklistLoginsImpl( + GetLoginsRequest* request) { + std::vector<PasswordForm*> forms; + FillBlacklistLogins(&forms); + NotifyConsumer(request, forms); +} + +bool PasswordStoreKWallet::FillAutofillableLogins( + std::vector<PasswordForm*>* forms) { + return FillSomeLogins(true, forms); +} + +bool PasswordStoreKWallet::FillBlacklistLogins( + std::vector<PasswordForm*>* forms) { + return FillSomeLogins(false, forms); +} + void PasswordStoreKWallet::GetLoginsList(PasswordFormList* forms, - const PasswordForm& key, + const string& signon_realm, int wallet_handle) { // Is there an entry in the wallet? gboolean has_entry = false; dbus_g_proxy_call(proxy_, "hasEntry", &error_, - G_TYPE_INT, wallet_handle, // handle - G_TYPE_STRING, kKWalletFolder, // folder - G_TYPE_STRING, key.signon_realm.c_str(), // key - G_TYPE_STRING, kAppId, // appid + G_TYPE_INT, wallet_handle, // handle + G_TYPE_STRING, kKWalletFolder, // folder + G_TYPE_STRING, signon_realm.c_str(), // key + G_TYPE_STRING, kAppId, // appid G_TYPE_INVALID, G_TYPE_BOOLEAN, &has_entry, G_TYPE_INVALID); @@ -226,10 +298,10 @@ void PasswordStoreKWallet::GetLoginsList(PasswordFormList* forms, GArray* byte_array = NULL; dbus_g_proxy_call(proxy_, "readEntry", &error_, - G_TYPE_INT, wallet_handle, // handle - G_TYPE_STRING, kKWalletFolder, // folder - G_TYPE_STRING, key.signon_realm.c_str(), // key - G_TYPE_STRING, kAppId, // appid + G_TYPE_INT, wallet_handle, // handle + G_TYPE_STRING, kKWalletFolder, // folder + G_TYPE_STRING, signon_realm.c_str(), // key + G_TYPE_STRING, kAppId, // appid G_TYPE_INVALID, DBUS_TYPE_G_UCHAR_ARRAY, &byte_array, G_TYPE_INVALID); @@ -238,12 +310,30 @@ void PasswordStoreKWallet::GetLoginsList(PasswordFormList* forms, return; Pickle pickle(byte_array->data, byte_array->len); - DeserializeValue(key, pickle, forms); + DeserializeValue(signon_realm, pickle, forms); + g_array_free(byte_array, true); } void PasswordStoreKWallet::SetLoginsList(const PasswordFormList& forms, - const PasswordForm& key, + const string& signon_realm, int wallet_handle) { + if (forms.empty()) { + // No items left? Remove the entry from the wallet. + int ret = 0; + dbus_g_proxy_call(proxy_, "removeEntry", &error_, + G_TYPE_INT, wallet_handle, // handle + G_TYPE_STRING, kKWalletFolder, // folder + G_TYPE_STRING, signon_realm.c_str(), // key + G_TYPE_STRING, kAppId, // appid + G_TYPE_INVALID, + G_TYPE_INT, &ret, + G_TYPE_INVALID); + CheckError(); + if (ret != 0) + LOG(ERROR) << "Bad return code " << ret << " from kwallet removeEntry"; + return; + } + Pickle value; SerializeValue(forms, &value); @@ -255,74 +345,144 @@ void PasswordStoreKWallet::SetLoginsList(const PasswordFormList& forms, // Make the call. int ret = 0; dbus_g_proxy_call(proxy_, "writeEntry", &error_, - G_TYPE_INT, wallet_handle, // handle - G_TYPE_STRING, kKWalletFolder, // folder - G_TYPE_STRING, key.signon_realm.c_str(), // key - DBUS_TYPE_G_UCHAR_ARRAY, byte_array, // value - G_TYPE_STRING, kAppId, // appid + G_TYPE_INT, wallet_handle, // handle + G_TYPE_STRING, kKWalletFolder, // folder + G_TYPE_STRING, signon_realm.c_str(), // key + DBUS_TYPE_G_UCHAR_ARRAY, byte_array, // value + G_TYPE_STRING, kAppId, // appid G_TYPE_INVALID, G_TYPE_INT, &ret, G_TYPE_INVALID); g_array_free(byte_array, true); CheckError(); - if (ret) + if (ret != 0) LOG(ERROR) << "Bad return code " << ret << " from kwallet writeEntry"; } +bool PasswordStoreKWallet::FillSomeLogins(bool autofillable, + PasswordFormList* forms) { + AutoLock l(kwallet_lock_); + int wallet_handle = WalletHandle(); + if (wallet_handle == kInvalidKWalletHandle) + return false; + + // We could probably also use readEntryList here. + char** realm_list = NULL; + dbus_g_proxy_call(proxy_, "entryList", &error_, + G_TYPE_INT, wallet_handle, // handle + G_TYPE_STRING, kKWalletFolder, // folder + G_TYPE_STRING, kAppId, // appid + G_TYPE_INVALID, + G_TYPE_STRV, &realm_list, + G_TYPE_INVALID); + if (CheckError()) + return false; + + PasswordFormList all_forms; + for (char** realm = realm_list; *realm; ++realm) { + GArray* byte_array = NULL; + dbus_g_proxy_call(proxy_, "readEntry", &error_, + G_TYPE_INT, wallet_handle, // handle + G_TYPE_STRING, kKWalletFolder, // folder + G_TYPE_STRING, *realm, // key + G_TYPE_STRING, kAppId, // appid + G_TYPE_INVALID, + DBUS_TYPE_G_UCHAR_ARRAY, &byte_array, + G_TYPE_INVALID); + + if (CheckError() || !byte_array || !byte_array->len) + continue; + + Pickle pickle(byte_array->data, byte_array->len); + DeserializeValue(*realm, pickle, &all_forms); + g_array_free(byte_array, true); + } + g_strfreev(realm_list); + + // We have to read all the entries, and then filter them here. + forms->reserve(forms->size() + all_forms.size()); + for (size_t i = 0; i < all_forms.size(); ++i) { + if (all_forms[i]->blacklisted_by_user == !autofillable) + forms->push_back(all_forms[i]); + else + delete all_forms[i]; + } + + return true; +} + bool PasswordStoreKWallet::CompareForms(const PasswordForm& a, - const PasswordForm& b) { + const PasswordForm& b, + bool update_check) { + // An update check doesn't care about the submit element. + if (!update_check && a.submit_element != b.submit_element) + return false; return a.origin == b.origin && a.password_element == b.password_element && a.signon_realm == b.signon_realm && - a.submit_element == b.submit_element && a.username_element == b.username_element && a.username_value == b.username_value; } void PasswordStoreKWallet::SerializeValue(const PasswordFormList& forms, Pickle* pickle) { - pickle->WriteInt(forms.size()); + pickle->WriteInt(kPickleVersion); + pickle->WriteSize(forms.size()); for (PasswordFormList::const_iterator it = forms.begin() ; it != forms.end() ; ++it) { const PasswordForm* form = *it; pickle->WriteInt(form->scheme); pickle->WriteString(form->origin.spec()); pickle->WriteString(form->action.spec()); - pickle->WriteWString(form->username_element); - pickle->WriteWString(form->username_value); - pickle->WriteWString(form->password_element); - pickle->WriteWString(form->password_value); - pickle->WriteWString(form->submit_element); + pickle->WriteString16(form->username_element); + pickle->WriteString16(form->username_value); + pickle->WriteString16(form->password_element); + pickle->WriteString16(form->password_value); + pickle->WriteString16(form->submit_element); pickle->WriteBool(form->ssl_valid); pickle->WriteBool(form->preferred); pickle->WriteBool(form->blacklisted_by_user); + pickle->WriteInt64(form->date_created.ToTimeT()); } } -void PasswordStoreKWallet::DeserializeValue(const PasswordForm& key, +void PasswordStoreKWallet::DeserializeValue(const string& signon_realm, const Pickle& pickle, PasswordFormList* forms) { void* iter = NULL; - int count = 0; - pickle.ReadInt(&iter, &count); + int version = -1; + pickle.ReadInt(&iter, &version); + if (version != kPickleVersion) { + // This is the only version so far, so anything else is an error. + return; + } + + size_t count = 0; + pickle.ReadSize(&iter, &count); - for (int i = 0; i < count; ++i) { + forms->reserve(forms->size() + count); + for (size_t i = 0; i < count; ++i) { PasswordForm* form = new PasswordForm(); - form->signon_realm.assign(key.signon_realm); + form->signon_realm.assign(signon_realm); - pickle.ReadInt(&iter, reinterpret_cast<int*>(&form->scheme)); + int scheme = 0; + pickle.ReadInt(&iter, &scheme); + form->scheme = static_cast<PasswordForm::Scheme>(scheme); ReadGURL(pickle, &iter, &form->origin); ReadGURL(pickle, &iter, &form->action); - pickle.ReadWString(&iter, &form->username_element); - pickle.ReadWString(&iter, &form->username_value); - pickle.ReadWString(&iter, &form->password_element); - pickle.ReadWString(&iter, &form->password_value); - pickle.ReadWString(&iter, &form->submit_element); + pickle.ReadString16(&iter, &form->username_element); + pickle.ReadString16(&iter, &form->username_value); + pickle.ReadString16(&iter, &form->password_element); + pickle.ReadString16(&iter, &form->password_value); + pickle.ReadString16(&iter, &form->submit_element); pickle.ReadBool(&iter, &form->ssl_valid); pickle.ReadBool(&iter, &form->preferred); pickle.ReadBool(&iter, &form->blacklisted_by_user); + int64 date_created = 0; + pickle.ReadInt64(&iter, &date_created); + form->date_created = base::Time::FromTimeT(date_created); forms->push_back(form); } } diff --git a/chrome/browser/password_manager/password_store_kwallet.h b/chrome/browser/password_manager/password_store_kwallet.h index 317cbdb..f7835fe 100644 --- a/chrome/browser/password_manager/password_store_kwallet.h +++ b/chrome/browser/password_manager/password_store_kwallet.h @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -12,8 +12,9 @@ #include <vector> #include "base/lock.h" -#include "base/thread.h" +#include "chrome/browser/password_manager/login_database.h" #include "chrome/browser/password_manager/password_store.h" +#include "chrome/browser/webdata/web_data_service.h" #include "webkit/glue/password_form.h" class Pickle; @@ -22,38 +23,54 @@ class Task; class PasswordStoreKWallet : public PasswordStore { public: - PasswordStoreKWallet(); + PasswordStoreKWallet(LoginDatabase* login_db, + Profile* profile, + WebDataService* web_data_service); bool Init(); private: - typedef std::vector<PasswordForm*> PasswordFormList; + typedef std::vector<webkit_glue::PasswordForm*> PasswordFormList; virtual ~PasswordStoreKWallet(); // Implements PasswordStore interface. - void AddLoginImpl(const PasswordForm& form); - void UpdateLoginImpl(const PasswordForm& form); - void RemoveLoginImpl(const PasswordForm& form); - void GetLoginsImpl(GetLoginsRequest* request); - - // Initialisation. + virtual void AddLoginImpl(const webkit_glue::PasswordForm& form); + virtual void UpdateLoginImpl(const webkit_glue::PasswordForm& form); + virtual void RemoveLoginImpl(const webkit_glue::PasswordForm& form); + virtual void RemoveLoginsCreatedBetweenImpl(const base::Time& delete_begin, + const base::Time& delete_end); + virtual void GetLoginsImpl(GetLoginsRequest* request, + const webkit_glue::PasswordForm& form); + virtual void GetAutofillableLoginsImpl(GetLoginsRequest* request); + virtual void GetBlacklistLoginsImpl(GetLoginsRequest* request); + virtual bool FillAutofillableLogins( + std::vector<webkit_glue::PasswordForm*>* forms); + virtual bool FillBlacklistLogins( + std::vector<webkit_glue::PasswordForm*>* forms); + + // Initialization. bool StartKWalletd(); bool InitWallet(); - // Reads a list of PasswordForms from the wallet that match the signon_realm - // of key. - void GetLoginsList(PasswordFormList* forms, const PasswordForm& key, + // Reads a list of PasswordForms from the wallet that match the signon_realm. + void GetLoginsList(PasswordFormList* forms, + const std::string& signon_realm, int wallet_handle); - // Writes a list of PasswordForms to the wallet with the signon_realm from - // key. Overwrites any existing list for this key. - void SetLoginsList(const PasswordFormList& forms, const PasswordForm& key, + // Writes a list of PasswordForms to the wallet with the given signon_realm. + // Overwrites any existing list for this signon_realm. Removes the entry if + // |forms| is empty. + void SetLoginsList(const PasswordFormList& forms, + const std::string& signon_realm, int wallet_handle); - // Checks if the last dbus call returned an error. If it did, logs the error + // Helper for FillAutofillableLogins() and FillBlacklistLogins(). + bool FillSomeLogins(bool autofillable, PasswordFormList* forms); + + // Checks if the last DBus call returned an error. If it did, logs the error // message, frees it and returns true. - // This must be called after every dbus call. + // This must be called after every DBus call. bool CheckError(); // Opens the wallet and ensures that the "Chrome Form Data" folder exists. @@ -61,27 +78,35 @@ class PasswordStoreKWallet : public PasswordStore { int WalletHandle(); // Compares two PasswordForms and returns true if they are the same. - // Checks only the fields that we persist in KWallet, and ignores - // password_value. - static bool CompareForms(const PasswordForm& a, const PasswordForm& b); + // If |update_check| is false, we only check the fields that are checked by + // LoginDatabase::UpdateLogin() when updating logins; otherwise, we check the + // fields that are checked by LoginDatabase::RemoveLogin() for removing them. + static bool CompareForms(const webkit_glue::PasswordForm& a, + const webkit_glue::PasswordForm& b, + bool update_check); // Serializes a list of PasswordForms to be stored in the wallet. static void SerializeValue(const PasswordFormList& forms, Pickle* pickle); // Deserializes a list of PasswordForms from the wallet. - static void DeserializeValue(const PasswordForm& key, const Pickle& pickle, + static void DeserializeValue(const std::string& signon_realm, + const Pickle& pickle, PasswordFormList* forms); - // Convenience function to read a GURL from a Pickle. Assumes the URL has + // Convenience function to read a GURL from a Pickle. Assumes the URL has // been written as a std::string. static void ReadGURL(const Pickle& pickle, void** iter, GURL* url); + // In case the fields in the pickle ever change, version them so we can try to + // read old pickles. (Note: do not eat old pickles past the expiration date.) + static const int kPickleVersion = 0; + // Name of the application - will appear in kwallet's dialogs. static const char* kAppId; // Name of the folder to store passwords in. static const char* kKWalletFolder; - // DBUS stuff. + // DBus stuff. static const char* kKWalletServiceName; static const char* kKWalletPath; static const char* kKWalletInterface; @@ -92,18 +117,18 @@ class PasswordStoreKWallet : public PasswordStore { // Invalid handle returned by WalletHandle(). static const int kInvalidKWalletHandle = -1; - // Controls all access to kwallet dbus calls. + // Controls all access to kwallet DBus calls. Lock kwallet_lock_; - // Error from the last dbus call. NULL when there's no error. Freed and + // Error from the last DBus call. NULL when there's no error. Freed and // cleared by CheckError(). GError* error_; - // Connection to the dbus session bus. + // Connection to the DBus session bus. DBusGConnection* connection_; - // Proxy to the kwallet dbus service. + // Proxy to the kwallet DBus service. DBusGProxy* proxy_; - // The name of the wallet we've opened. Set during Init(). + // The name of the wallet we've opened. Set during Init(). std::string wallet_name_; DISALLOW_COPY_AND_ASSIGN(PasswordStoreKWallet); |