Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(7)

Unified Diff: chrome/browser/password_manager/password_store_kwallet.cc

Issue 114057: Re-land the password store work from bug 8205, with changes that should fix b... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/password_manager/password_store_kwallet.cc
===================================================================
--- chrome/browser/password_manager/password_store_kwallet.cc (revision 0)
+++ chrome/browser/password_manager/password_store_kwallet.cc (revision 0)
@@ -0,0 +1,387 @@
+// Copyright (c) 2006-2009 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.
+
+#include "chrome/browser/password_manager/password_store_kwallet.h"
+
+#include <sstream>
+
+#include "base/logging.h"
+#include "base/md5.h"
+#include "base/pickle.h"
+#include "base/string_util.h"
+#include "base/task.h"
+
+using std::string;
+using std::vector;
+
+const char* PasswordStoreKWallet::kAppId = "Chrome";
+const char* PasswordStoreKWallet::kKWalletFolder = "Chrome Form Data";
+
+const char* PasswordStoreKWallet::kKWalletServiceName = "org.kde.kwalletd";
+const char* PasswordStoreKWallet::kKWalletPath = "/modules/kwalletd";
+const char* PasswordStoreKWallet::kKWalletInterface = "org.kde.KWallet";
+const char* PasswordStoreKWallet::kKLauncherServiceName = "org.kde.klauncher";
+const char* PasswordStoreKWallet::kKLauncherPath = "/KLauncher";
+const char* PasswordStoreKWallet::kKLauncherInterface = "org.kde.KLauncher";
+
+PasswordStoreKWallet::PasswordStoreKWallet()
+ : error_(NULL),
+ connection_(NULL),
+ proxy_(NULL) {
+}
+
+PasswordStoreKWallet::~PasswordStoreKWallet() {
+ if (proxy_) {
+ g_object_unref(proxy_);
+ }
+}
+
+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())
+ g_thread_init(NULL);
+ dbus_g_thread_init();
+
+ // Get a connection to the session bus.
+ connection_ = dbus_g_bus_get(DBUS_BUS_SESSION, &error_);
+ if (CheckError())
+ return false;
+
+ if (!StartKWalletd()) return false;
+ if (!InitWallet()) return false;
+
+ return true;
+}
+
+bool PasswordStoreKWallet::StartKWalletd() {
+ // Sadly kwalletd doesn't use DBUS activation, so we have to make a call to
+ // klauncher to start it.
+ DBusGProxy* klauncher_proxy =
+ dbus_g_proxy_new_for_name(connection_, kKLauncherServiceName,
+ kKLauncherPath, kKLauncherInterface);
+
+ char* empty_string_list = NULL;
+ int ret = 1;
+ char* error = NULL;
+ dbus_g_proxy_call(klauncher_proxy, "start_service_by_desktop_name", &error_,
+ G_TYPE_STRING, "kwalletd", // serviceName
+ G_TYPE_STRV, &empty_string_list, // urls
+ G_TYPE_STRV, &empty_string_list, // envs
+ G_TYPE_STRING, "", // startup_id
+ G_TYPE_BOOLEAN, (gboolean) false, // blind
+ G_TYPE_INVALID,
+ G_TYPE_INT, &ret, // result
+ G_TYPE_STRING, NULL, // dubsName
+ G_TYPE_STRING, &error, // error
+ G_TYPE_INT, NULL, // pid
+ G_TYPE_INVALID);
+
+ if (error && *error) {
+ LOG(ERROR) << "Error launching kwalletd: " << error;
+ ret = 1; // Make sure we return false after freeing.
+ }
+
+ g_free(error);
+ g_object_unref(klauncher_proxy);
+
+ if (CheckError() || ret != 0)
+ return false;
+ return true;
+}
+
+bool PasswordStoreKWallet::InitWallet() {
+ // Make a proxy to KWallet.
+ proxy_ = dbus_g_proxy_new_for_name(connection_, kKWalletServiceName,
+ kKWalletPath, kKWalletInterface);
+
+ // Check KWallet is enabled.
+ gboolean is_enabled = false;
+ dbus_g_proxy_call(proxy_, "isEnabled", &error_,
+ G_TYPE_INVALID,
+ G_TYPE_BOOLEAN, &is_enabled,
+ G_TYPE_INVALID);
+ if (CheckError() || !is_enabled)
+ return false;
+
+ // Get the wallet name.
+ char* wallet_name = NULL;
+ dbus_g_proxy_call(proxy_, "networkWallet", &error_,
+ G_TYPE_INVALID,
+ G_TYPE_STRING, &wallet_name,
+ G_TYPE_INVALID);
+ if (CheckError() || !wallet_name)
+ return false;
+
+ wallet_name_.assign(wallet_name);
+ g_free(wallet_name);
+
+ return true;
+}
+
+void PasswordStoreKWallet::AddLoginImpl(const PasswordForm& form) {
+ AutoLock l(kwallet_lock_);
+ int wallet_handle = WalletHandle();
+ if (wallet_handle == kInvalidKWalletHandle)
+ return;
+
+ PasswordFormList forms;
+ GetLoginsList(&forms, form, wallet_handle);
+
+ forms.push_back(const_cast<PasswordForm*>(&form));
+
+ SetLoginsList(forms, form, wallet_handle);
+}
+
+void PasswordStoreKWallet::UpdateLoginImpl(const PasswordForm& form) {
+ AutoLock l(kwallet_lock_);
+ int wallet_handle = WalletHandle();
+ if (wallet_handle == kInvalidKWalletHandle)
+ return;
+
+ PasswordFormList forms;
+ GetLoginsList(&forms, form, 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));
+ }
+ }
+
+ SetLoginsList(forms, form, wallet_handle);
+}
+
+void PasswordStoreKWallet::RemoveLoginImpl(const PasswordForm& form) {
+ AutoLock l(kwallet_lock_);
+ int wallet_handle = WalletHandle();
+ if (wallet_handle == kInvalidKWalletHandle)
+ return;
+
+ PasswordFormList forms;
+ GetLoginsList(&forms, form, wallet_handle);
+
+ for (uint i = 0; i < forms.size(); ++i) {
+ if (CompareForms(form, *forms[i])) {
+ forms.erase(forms.begin() + i);
+ --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
+ G_TYPE_INVALID,
+ G_TYPE_INT, &ret,
+ 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);
+ }
+}
+
+void PasswordStoreKWallet::GetLoginsImpl(GetLoginsRequest* request) {
+ PasswordFormList forms;
+
+ AutoLock l(kwallet_lock_);
+ int wallet_handle = WalletHandle();
+ if (wallet_handle != kInvalidKWalletHandle)
+ GetLoginsList(&forms, request->form, wallet_handle);
+
+ NotifyConsumer(request, forms);
+}
+
+void PasswordStoreKWallet::GetLoginsList(PasswordFormList* forms,
+ const PasswordForm& key,
+ 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_INVALID,
+ G_TYPE_BOOLEAN, &has_entry,
+ G_TYPE_INVALID);
+
+ if (CheckError() || !has_entry)
+ return;
+
+ 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_INVALID,
+ DBUS_TYPE_G_UCHAR_ARRAY, &byte_array,
+ G_TYPE_INVALID);
+
+ if (CheckError() || !byte_array || !byte_array->len)
+ return;
+
+ Pickle pickle(byte_array->data, byte_array->len);
+ DeserializeValue(key, pickle, forms);
+}
+
+void PasswordStoreKWallet::SetLoginsList(const PasswordFormList& forms,
+ const PasswordForm& key,
+ int wallet_handle) {
+ Pickle value;
+ SerializeValue(forms, &value);
+
+ // Convert the pickled bytes to a GByteArray.
+ GArray* byte_array = g_array_sized_new(false, false, sizeof(char),
+ value.size());
+ g_array_append_vals(byte_array, value.data(), value.size());
+
+ // 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_INVALID,
+ G_TYPE_INT, &ret,
+ G_TYPE_INVALID);
+ g_array_free(byte_array, true);
+
+ CheckError();
+ if (ret)
+ LOG(ERROR) << "Bad return code " << ret << " from kwallet writeEntry";
+}
+
+bool PasswordStoreKWallet::CompareForms(const PasswordForm& a,
+ const PasswordForm& b) {
+ 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());
+ 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->WriteBool(form->ssl_valid);
+ pickle->WriteBool(form->preferred);
+ pickle->WriteBool(form->blacklisted_by_user);
+ }
+}
+
+void PasswordStoreKWallet::DeserializeValue(const PasswordForm& key,
+ const Pickle& pickle,
+ PasswordFormList* forms) {
+ void* iter = NULL;
+
+ int count = 0;
+ pickle.ReadInt(&iter, &count);
+
+ for (int i = 0; i < count; ++i) {
+ PasswordForm* form = new PasswordForm();
+ form->signon_realm.assign(key.signon_realm);
+
+ pickle.ReadInt(&iter, reinterpret_cast<int*>(&form->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.ReadBool(&iter, &form->ssl_valid);
+ pickle.ReadBool(&iter, &form->preferred);
+ pickle.ReadBool(&iter, &form->blacklisted_by_user);
+ forms->push_back(form);
+ }
+}
+
+void PasswordStoreKWallet::ReadGURL(const Pickle& pickle, void** iter,
+ GURL* url) {
+ string url_string;
+ pickle.ReadString(iter, &url_string);
+ *url = GURL(url_string);
+}
+
+bool PasswordStoreKWallet::CheckError() {
+ if (error_) {
+ LOG(ERROR) << "Failed to complete KWallet call: " << error_->message;
+ g_error_free(error_);
+ error_ = NULL;
+ return true;
+ }
+ return false;
+}
+
+int PasswordStoreKWallet::WalletHandle() {
+ // Open the wallet.
+ int handle = kInvalidKWalletHandle;
+ dbus_g_proxy_call(proxy_, "open", &error_,
+ G_TYPE_STRING, wallet_name_.c_str(), // wallet
+ G_TYPE_INT64, 0LL, // wid
+ G_TYPE_STRING, kAppId, // appid
+ G_TYPE_INVALID,
+ G_TYPE_INT, &handle,
+ G_TYPE_INVALID);
+ if (CheckError() || handle == kInvalidKWalletHandle)
+ return kInvalidKWalletHandle;
+
+ // Check if our folder exists.
+ gboolean has_folder = false;
+ dbus_g_proxy_call(proxy_, "hasFolder", &error_,
+ G_TYPE_INT, handle, // handle
+ G_TYPE_STRING, kKWalletFolder, // folder
+ G_TYPE_STRING, kAppId, // appid
+ G_TYPE_INVALID,
+ G_TYPE_BOOLEAN, &has_folder,
+ G_TYPE_INVALID);
+ if (CheckError())
+ return kInvalidKWalletHandle;
+
+ // Create it if it didn't.
+ if (!has_folder) {
+ gboolean success = false;
+ dbus_g_proxy_call(proxy_, "createFolder", &error_,
+ G_TYPE_INT, handle, // handle
+ G_TYPE_STRING, kKWalletFolder, // folder
+ G_TYPE_STRING, kAppId, // appid
+ G_TYPE_INVALID,
+ G_TYPE_BOOLEAN, &success,
+ G_TYPE_INVALID);
+ if (CheckError() || !success)
+ return kInvalidKWalletHandle;
+ }
+
+ return handle;
+}
« no previous file with comments | « chrome/browser/password_manager/password_store_kwallet.h ('k') | chrome/browser/password_manager/password_store_win.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698