Chromium Code Reviews| Index: chrome/browser/password_manager/native_backend_kwallet_x.cc |
| =================================================================== |
| --- chrome/browser/password_manager/native_backend_kwallet_x.cc (revision 100563) |
| +++ chrome/browser/password_manager/native_backend_kwallet_x.cc (working copy) |
| @@ -4,18 +4,20 @@ |
| #include "chrome/browser/password_manager/native_backend_kwallet_x.h" |
| -#include <sstream> |
| +#include <vector> |
| #include "base/logging.h" |
| #include "base/pickle.h" |
| #include "base/stl_util.h" |
| #include "base/stringprintf.h" |
| +#include "base/synchronization/waitable_event.h" |
| #include "content/browser/browser_thread.h" |
| +#include "dbus/bus.h" |
| +#include "dbus/message.h" |
| +#include "dbus/object_proxy.h" |
| #include "grit/chromium_strings.h" |
| #include "ui/base/l10n/l10n_util.h" |
| -using std::string; |
| -using std::vector; |
| using webkit_glue::PasswordForm; |
| // We could localize this string, but then changing your locale would cause |
| @@ -32,7 +34,6 @@ |
| NativeBackendKWallet::NativeBackendKWallet(LocalProfileId id, |
| PrefService* prefs) |
| : profile_id_(id), prefs_(prefs), |
| - error_(NULL), connection_(NULL), proxy_(NULL), |
| app_name_(l10n_util::GetStringUTF8(IDS_PRODUCT_NAME)) { |
| if (PasswordStoreX::PasswordsUseLocalProfileId(prefs)) { |
| folder_name_ = GetProfileSpecificFolderName(); |
| @@ -45,87 +46,152 @@ |
| } |
| NativeBackendKWallet::~NativeBackendKWallet() { |
| - if (proxy_) |
| - g_object_unref(proxy_); |
| + // This destructor is called on the thread that is destroying the Profile |
| + // containing the PasswordStore that owns this NativeBackend. Generally that |
| + // won't be the DB thread; it will be the UI thread. So we post a message to |
| + // shut it down on the DB thread, and it will be destructed afterward when the |
| + // scoped_refptr<dbus::Bus> goes out of scope. The NativeBackend will be |
| + // destroyed before that occurs, but that's OK. |
| + if (session_bus_.get()) { |
| + BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, |
| + NewRunnableMethod( |
|
satorux1
2011/09/12 19:28:57
base::Bind is preferable.
Mike Mammarella
2011/09/12 21:26:13
I am inclined to stick with this for now since I k
satorux1
2011/09/12 22:28:21
That's fine, but it should be as easy as:
Browser
|
| + session_bus_.get(), |
| + &dbus::Bus::ShutdownAndBlock)); |
| + } |
| } |
| bool NativeBackendKWallet::Init() { |
| - // Get a connection to the session bus. |
| - connection_ = dbus_g_bus_get(DBUS_BUS_SESSION, &error_); |
| - if (CheckError()) |
| - return false; |
| + // We must synchronously do a few DBus calls to figure out if initialization |
| + // succeeds, but later, we'll want to do most work on the DB thread. So we |
| + // have to do the initialization on the DB thread here too, and wait for it. |
| + scoped_refptr<dbus::Bus> optional_bus; // Will construct its own. |
| + bool success = false; |
| + base::WaitableEvent event(false, false); |
| + BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, |
| + NewRunnableMethod( |
|
satorux1
2011/09/12 19:28:57
ditto.
Mike Mammarella
2011/09/12 21:26:13
same
|
| + this, &NativeBackendKWallet::InitWithBus, |
| + optional_bus, &event, &success)); |
| + event.Wait(); |
| + return success; |
| +} |
| - if (!InitWallet()) { |
| - // kwalletd may not be running. Try to start it and try again. |
| - if (!StartKWalletd() || !InitWallet()) |
| - return false; |
| +// NativeBackendKWallet isn't reference counted, but the one place we post a |
| +// message to it (in InitWithBus below) waits for the task to run. So we can |
| +// disable needing reference counting safely here. |
| +template<> |
| +struct RunnableMethodTraits<NativeBackendKWallet> { |
| + void RetainCallee(NativeBackendKWallet*) {} |
| + void ReleaseCallee(NativeBackendKWallet*) {} |
| +}; |
| + |
| +void NativeBackendKWallet::InitWithBus(scoped_refptr<dbus::Bus> optional_bus, |
| + base::WaitableEvent* event, |
| + bool* success) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); |
| + DCHECK(!session_bus_.get()); |
| + if (optional_bus.get()) { |
|
satorux1
2011/09/12 19:28:57
This is a bit tricky. You might want to add a comm
Mike Mammarella
2011/09/12 21:26:13
Done.
|
| + session_bus_ = optional_bus; |
| + } else { |
| + // Get a connection to the session bus. |
| + dbus::Bus::Options options; |
| + options.bus_type = dbus::Bus::SESSION; |
| + options.connection_type = dbus::Bus::PRIVATE; |
| + session_bus_ = new dbus::Bus(options); |
| } |
| - |
| - return true; |
| + kwallet_proxy_ = |
| + session_bus_->GetObjectProxy(kKWalletServiceName, kKWalletPath); |
| + // kwalletd may not be running. If it fails to initialize, try to start it |
| + // and then try to initialize it again. (Note the short-circuit evaluation.) |
| + *success = InitWallet() || (StartKWalletd() && InitWallet()); |
|
satorux1
2011/09/12 19:28:57
I wasn't sure if || had higher precedence than =.
Mike Mammarella
2011/09/12 21:26:13
Some of the operators (the bitwise ones especially
|
| + if (event) |
| + event->Signal(); |
| } |
| bool NativeBackendKWallet::StartKWalletd() { |
|
satorux1
2011/09/12 19:28:57
You might want to add
DCHECK(BrowserThread::Curr
Mike Mammarella
2011/09/12 21:26:13
Done.
|
| - // Sadly kwalletd doesn't use DBUS activation, so we have to make a call to |
| + // 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); |
| + dbus::ObjectProxy* klauncher = |
| + session_bus_->GetObjectProxy(kKLauncherServiceName, kKLauncherPath); |
| - 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. |
| + dbus::MethodCall method_call(kKLauncherInterface, |
| + "start_service_by_desktop_name"); |
| + dbus::MessageWriter builder(&method_call); |
| + dbus::MessageWriter empty(&method_call); |
| + builder.AppendString("kwalletd"); // serviceName |
| + builder.OpenArray("s", &empty); // urls |
| + builder.CloseContainer(&empty); |
| + builder.OpenArray("s", &empty); // envs |
| + builder.CloseContainer(&empty); |
| + builder.AppendString(""); // startup_id |
| + builder.AppendBool(false); // blind |
| + scoped_ptr<dbus::Response> response( |
| + klauncher->CallMethodAndBlock( |
| + &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT)); |
| + if (!response.get()) { |
| + LOG(ERROR) << "Error contacting klauncher to start kwalletd"; |
| + return false; |
| } |
| + dbus::MessageReader reader(response.get()); |
| + int32_t ret = -1; |
| + std::string dbus_name; |
| + std::string error; |
| + int32_t pid = -1; |
| + if (!reader.PopInt32(&ret) || !reader.PopString(&dbus_name) || |
| + !reader.PopString(&error) || !reader.PopInt32(&pid)) { |
| + LOG(ERROR) << "Error reading response from klauncher to start kwalletd: " |
| + << response->ToString(); |
| + return false; |
| + } |
| + if (!error.empty() || ret) { |
| + LOG(ERROR) << "Error launching kwalletd: error '" << error << "' " |
| + << " (code " << ret << ")"; |
| + return false; |
| + } |
| - g_free(error); |
| - g_object_unref(klauncher_proxy); |
| - |
| - if (CheckError() || ret != 0) |
| - return false; |
| return true; |
| } |
| bool NativeBackendKWallet::InitWallet() { |
|
satorux1
2011/09/12 19:28:57
You might want to add
DCHECK(BrowserThread::Curr
Mike Mammarella
2011/09/12 21:26:13
Done.
|
| - // Make a proxy to KWallet. |
| - proxy_ = dbus_g_proxy_new_for_name(connection_, kKWalletServiceName, |
| - kKWalletPath, kKWalletInterface); |
| + { |
| + // Check that KWallet is enabled. |
| + dbus::MethodCall method_call(kKWalletInterface, "isEnabled"); |
| + scoped_ptr<dbus::Response> response( |
| + kwallet_proxy_->CallMethodAndBlock( |
| + &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT)); |
| + if (!response.get()) { |
| + LOG(ERROR) << "Error contacting kwalletd (isEnabled)"; |
| + return false; |
| + } |
| + dbus::MessageReader reader(response.get()); |
| + bool enabled = false; |
| + if (!reader.PopBool(&enabled)) { |
| + LOG(ERROR) << "Error reading response from kwalletd (isEnabled): " |
| + << response->ToString(); |
| + return false; |
| + } |
| + // Not enabled? Don't use KWallet. But also don't warn here. |
| + if (!enabled) |
| + return false; |
|
satorux1
2011/09/12 19:28:57
VLOG(1) may be helpful for debugging?
Mike Mammarella
2011/09/12 21:26:13
Done.
|
| + } |
| - // 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. |
| + dbus::MethodCall method_call(kKWalletInterface, "networkWallet"); |
| + scoped_ptr<dbus::Response> response( |
| + kwallet_proxy_->CallMethodAndBlock( |
| + &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT)); |
| + if (!response.get()) { |
| + LOG(ERROR) << "Error contacting kwalletd (networkWallet)"; |
| + return false; |
| + } |
| + dbus::MessageReader reader(response.get()); |
| + if (!reader.PopString(&wallet_name_)) { |
| + LOG(ERROR) << "Error reading response from kwalletd (networkWallet): " |
| + << response->ToString(); |
| + 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; |
| } |
| @@ -209,39 +275,69 @@ |
| 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, folder_name_.c_str(), // folder |
| - G_TYPE_STRING, app_name_.c_str(), // appid |
| - G_TYPE_INVALID, |
| - G_TYPE_STRV, &realm_list, |
| - G_TYPE_INVALID); |
| - if (CheckError()) |
| - return false; |
| + std::vector<std::string> realm_list; |
| + { |
| + dbus::MethodCall method_call(kKWalletInterface, "entryList"); |
| + dbus::MessageWriter builder(&method_call); |
| + builder.AppendInt32(wallet_handle); // handle |
| + builder.AppendString(folder_name_); // folder |
| + builder.AppendString(app_name_); // appid |
| + scoped_ptr<dbus::Response> response( |
| + kwallet_proxy_->CallMethodAndBlock( |
| + &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT)); |
| + if (!response.get()) { |
| + LOG(ERROR) << "Error contacting kwalletd (entryList)"; |
| + return false; |
| + } |
| + dbus::MessageReader reader(response.get()); |
| + dbus::MessageReader array(response.get()); |
| + if (!reader.PopArray(&array)) { |
| + LOG(ERROR) << "Error reading response from kwalletd (entryList): " |
| + << response->ToString(); |
| + return false; |
| + } |
| + while (array.HasMoreData()) { |
| + std::string realm; |
| + if (!array.PopString(&realm)) { |
| + LOG(ERROR) << "Error reading response from kwalletd (entryList): " |
| + << response->ToString(); |
| + return false; |
| + } |
| + realm_list.push_back(realm); |
| + } |
| + } |
| bool ok = true; |
| - 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, folder_name_.c_str(), // folder |
| - G_TYPE_STRING, *realm, // key |
| - G_TYPE_STRING, app_name_.c_str(), // appid |
| - G_TYPE_INVALID, |
| - DBUS_TYPE_G_UCHAR_ARRAY, &byte_array, |
| - G_TYPE_INVALID); |
| - |
| - if (CheckError() || !byte_array || |
| - !CheckSerializedValue(byte_array, *realm)) { |
| + for (size_t i = 0; i < realm_list.size(); ++i) { |
| + const std::string& signon_realm = realm_list[i]; |
| + dbus::MethodCall method_call(kKWalletInterface, "readEntry"); |
| + dbus::MessageWriter builder(&method_call); |
| + builder.AppendInt32(wallet_handle); // handle |
| + builder.AppendString(folder_name_); // folder |
| + builder.AppendString(signon_realm); // key |
| + builder.AppendString(app_name_); // appid |
| + scoped_ptr<dbus::Response> response( |
| + kwallet_proxy_->CallMethodAndBlock( |
| + &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT)); |
| + if (!response.get()) { |
| + LOG(ERROR) << "Error contacting kwalletd (readEntry)"; |
| continue; |
| } |
| + dbus::MessageReader reader(response.get()); |
| + uint8_t* bytes = NULL; |
| + size_t length = 0; |
| + if (!reader.PopArrayOfBytes(&bytes, &length)) { |
| + LOG(ERROR) << "Error reading response from kwalletd (readEntry): " |
| + << response->ToString(); |
| + continue; |
| + } |
| + if (!bytes || !CheckSerializedValue(bytes, length, signon_realm)) |
| + continue; |
| - string signon_realm(*realm); |
| - Pickle pickle(byte_array->data, byte_array->len); |
| + // Can't we all just agree on whether bytes are signed or not? Please? |
| + Pickle pickle(reinterpret_cast<const char*>(bytes), length); |
| PasswordFormList all_forms; |
| DeserializeValue(signon_realm, pickle, &all_forms); |
| - g_array_free(byte_array, true); |
| PasswordFormList kept_forms; |
| kept_forms.reserve(all_forms.size()); |
| @@ -258,7 +354,6 @@ |
| ok = false; |
| STLDeleteElements(&kept_forms); |
| } |
| - g_strfreev(realm_list); |
| return ok; |
| } |
| @@ -294,51 +389,74 @@ |
| } |
| bool NativeBackendKWallet::GetLoginsList(PasswordFormList* forms, |
| - const string& signon_realm, |
| + const std::string& signon_realm, |
| int wallet_handle) { |
|
satorux1
2011/09/12 19:28:57
You might want to add
DCHECK(BrowserThread::Curr
Mike Mammarella
2011/09/12 21:26:13
Although this method doesn't actually call WalletH
|
| // 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, folder_name_.c_str(), // folder |
| - G_TYPE_STRING, signon_realm.c_str(), // key |
| - G_TYPE_STRING, app_name_.c_str(), // appid |
| - G_TYPE_INVALID, |
| - G_TYPE_BOOLEAN, &has_entry, |
| - G_TYPE_INVALID); |
| - |
| - if (CheckError()) |
| - return false; |
| - if (!has_entry) { |
| - // This is not an error. There just isn't a matching entry. |
| - return true; |
| + { |
| + dbus::MethodCall method_call(kKWalletInterface, "hasEntry"); |
| + dbus::MessageWriter builder(&method_call); |
| + builder.AppendInt32(wallet_handle); // handle |
| + builder.AppendString(folder_name_); // folder |
| + builder.AppendString(signon_realm); // key |
| + builder.AppendString(app_name_); // appid |
| + scoped_ptr<dbus::Response> response( |
| + kwallet_proxy_->CallMethodAndBlock( |
| + &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT)); |
| + if (!response.get()) { |
| + LOG(ERROR) << "Error contacting kwalletd (hasEntry)"; |
| + return false; |
| + } |
| + dbus::MessageReader reader(response.get()); |
| + bool has_entry = false; |
| + if (!reader.PopBool(&has_entry)) { |
| + LOG(ERROR) << "Error reading response from kwalletd (hasEntry): " |
| + << response->ToString(); |
| + return false; |
| + } |
| + if (!has_entry) { |
| + // This is not an error. There just isn't a matching entry. |
| + return true; |
| + } |
| } |
| - GArray* byte_array = NULL; |
| - dbus_g_proxy_call(proxy_, "readEntry", &error_, |
| - G_TYPE_INT, wallet_handle, // handle |
| - G_TYPE_STRING, folder_name_.c_str(), // folder |
| - G_TYPE_STRING, signon_realm.c_str(), // key |
| - G_TYPE_STRING, app_name_.c_str(), // appid |
| - G_TYPE_INVALID, |
| - DBUS_TYPE_G_UCHAR_ARRAY, &byte_array, |
| - G_TYPE_INVALID); |
| + { |
| + dbus::MethodCall method_call(kKWalletInterface, "readEntry"); |
| + dbus::MessageWriter builder(&method_call); |
| + builder.AppendInt32(wallet_handle); // handle |
| + builder.AppendString(folder_name_); // folder |
| + builder.AppendString(signon_realm); // key |
| + builder.AppendString(app_name_); // appid |
| + scoped_ptr<dbus::Response> response( |
| + kwallet_proxy_->CallMethodAndBlock( |
| + &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT)); |
| + if (!response.get()) { |
| + LOG(ERROR) << "Error contacting kwalletd (readEntry)"; |
| + return false; |
| + } |
| + dbus::MessageReader reader(response.get()); |
| + uint8_t* bytes = NULL; |
| + size_t length = 0; |
| + if (!reader.PopArrayOfBytes(&bytes, &length)) { |
| + LOG(ERROR) << "Error reading response from kwalletd (readEntry): " |
| + << response->ToString(); |
| + return false; |
| + } |
| + if (!bytes) |
| + return false; |
| + if (!CheckSerializedValue(bytes, length, signon_realm)) { |
| + // This is weird, but we choose not to call it an error. There is an |
| + // invalid entry somehow, but by just ignoring it, we make it easier to |
| + // repair without having to delete it using kwalletmanager (that is, by |
| + // just saving a new password within this realm to overwrite it). |
|
satorux1
2011/09/12 19:28:57
Worth adding a LOG(WARNING) or something?
Mike Mammarella
2011/09/12 21:26:13
CheckSerializedValue() has one.
|
| + return true; |
| + } |
| - if (CheckError() || !byte_array) |
| - return false; |
| - if (!CheckSerializedValue(byte_array, signon_realm.c_str())) { |
| - // This is weird, but we choose not to call it an error. There's an invalid |
| - // entry somehow, but by pretending it just doesn't exist, we make it easier |
| - // to repair without having to delete it using kwalletmanager (that is, by |
| - // just saving a new password within this realm to overwrite it). |
| - g_array_free(byte_array, true); |
| - return true; |
| + // Can't we all just agree on whether bytes are signed or not? Please? |
| + Pickle pickle(reinterpret_cast<const char*>(bytes), length); |
| + PasswordFormList all_forms; |
| + DeserializeValue(signon_realm, pickle, forms); |
| } |
| - Pickle pickle(byte_array->data, byte_array->len); |
| - DeserializeValue(signon_realm, pickle, forms); |
| - g_array_free(byte_array, true); |
| - |
| return true; |
| } |
| @@ -386,57 +504,97 @@ |
| bool NativeBackendKWallet::GetAllLogins(PasswordFormList* forms, |
| int wallet_handle) { |
|
satorux1
2011/09/12 19:28:57
You might want to add
DCHECK(BrowserThread::Curr
Mike Mammarella
2011/09/12 21:26:13
Same reasoning about WalletHandle().
|
| // 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, folder_name_.c_str(), // folder |
| - G_TYPE_STRING, app_name_.c_str(), // appid |
| - G_TYPE_INVALID, |
| - G_TYPE_STRV, &realm_list, |
| - G_TYPE_INVALID); |
| - if (CheckError()) |
| - return false; |
| + std::vector<std::string> realm_list; |
| + { |
| + dbus::MethodCall method_call(kKWalletInterface, "entryList"); |
| + dbus::MessageWriter builder(&method_call); |
| + builder.AppendInt32(wallet_handle); // handle |
| + builder.AppendString(folder_name_); // folder |
| + builder.AppendString(app_name_); // appid |
| + scoped_ptr<dbus::Response> response( |
| + kwallet_proxy_->CallMethodAndBlock( |
| + &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT)); |
| + if (!response.get()) { |
| + LOG(ERROR) << "Error contacting kwalletd (entryList)"; |
| + return false; |
| + } |
| + dbus::MessageReader reader(response.get()); |
| + dbus::MessageReader array(response.get()); |
| + if (!reader.PopArray(&array)) { |
| + LOG(ERROR) << "Error reading response from kwalletd (entryList): " |
| + << response->ToString(); |
| + return false; |
| + } |
| + while (array.HasMoreData()) { |
|
satorux1
2011/09/12 19:28:57
This is the second time I see this. I guess it's w
Mike Mammarella
2011/09/12 21:26:13
That would be useful. I'll consider adding one in
|
| + std::string realm; |
| + if (!array.PopString(&realm)) { |
| + LOG(ERROR) << "Error reading response from kwalletd (entryList): " |
| + << response->ToString(); |
| + return false; |
| + } |
| + realm_list.push_back(realm); |
| + } |
| + } |
| - 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, folder_name_.c_str(), // folder |
| - G_TYPE_STRING, *realm, // key |
| - G_TYPE_STRING, app_name_.c_str(), // appid |
| - G_TYPE_INVALID, |
| - DBUS_TYPE_G_UCHAR_ARRAY, &byte_array, |
| - G_TYPE_INVALID); |
| - |
| - if (CheckError() || !byte_array || |
| - !CheckSerializedValue(byte_array, *realm)) { |
| + for (size_t i = 0; i < realm_list.size(); ++i) { |
| + const std::string& signon_realm = realm_list[i]; |
| + dbus::MethodCall method_call(kKWalletInterface, "readEntry"); |
| + dbus::MessageWriter builder(&method_call); |
| + builder.AppendInt32(wallet_handle); // handle |
| + builder.AppendString(folder_name_); // folder |
| + builder.AppendString(signon_realm); // key |
| + builder.AppendString(app_name_); // appid |
| + scoped_ptr<dbus::Response> response( |
| + kwallet_proxy_->CallMethodAndBlock( |
| + &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT)); |
| + if (!response.get()) { |
| + LOG(ERROR) << "Error contacting kwalletd (readEntry)"; |
| continue; |
| } |
| + dbus::MessageReader reader(response.get()); |
| + uint8_t* bytes = NULL; |
| + size_t length = 0; |
| + if (!reader.PopArrayOfBytes(&bytes, &length)) { |
| + LOG(ERROR) << "Error reading response from kwalletd (readEntry): " |
| + << response->ToString(); |
| + continue; |
| + } |
| + if (!bytes || !CheckSerializedValue(bytes, length, signon_realm)) |
| + continue; |
| - Pickle pickle(byte_array->data, byte_array->len); |
| - DeserializeValue(*realm, pickle, forms); |
| - g_array_free(byte_array, true); |
| + // Can't we all just agree on whether bytes are signed or not? Please? |
| + Pickle pickle(reinterpret_cast<const char*>(bytes), length); |
| + PasswordFormList all_forms; |
| + DeserializeValue(signon_realm, pickle, forms); |
| } |
| - g_strfreev(realm_list); |
| return true; |
| } |
| bool NativeBackendKWallet::SetLoginsList(const PasswordFormList& forms, |
| - const string& signon_realm, |
| + const std::string& signon_realm, |
| int wallet_handle) { |
|
satorux1
2011/09/12 19:28:57
You might want to add
DCHECK(BrowserThread::Curr
Mike Mammarella
2011/09/12 21:26:13
Same.
|
| if (forms.empty()) { |
| // No items left? Remove the entry from the wallet. |
| + dbus::MethodCall method_call(kKWalletInterface, "removeEntry"); |
| + dbus::MessageWriter builder(&method_call); |
| + builder.AppendInt32(wallet_handle); // handle |
| + builder.AppendString(folder_name_); // folder |
| + builder.AppendString(signon_realm); // key |
| + builder.AppendString(app_name_); // appid |
| + scoped_ptr<dbus::Response> response( |
| + kwallet_proxy_->CallMethodAndBlock( |
| + &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT)); |
| + if (!response.get()) { |
| + LOG(ERROR) << "Error contacting kwalletd (removeEntry)"; |
| + return kInvalidKWalletHandle; |
| + } |
| + dbus::MessageReader reader(response.get()); |
| int ret = 0; |
| - dbus_g_proxy_call(proxy_, "removeEntry", &error_, |
| - G_TYPE_INT, wallet_handle, // handle |
| - G_TYPE_STRING, folder_name_.c_str(), // folder |
| - G_TYPE_STRING, signon_realm.c_str(), // key |
| - G_TYPE_STRING, app_name_.c_str(), // appid |
| - G_TYPE_INVALID, |
| - G_TYPE_INT, &ret, |
| - G_TYPE_INVALID); |
| - if (CheckError()) |
| + if (!reader.PopInt32(&ret)) { |
| + LOG(ERROR) << "Error reading response from kwalletd (removeEntry): " |
| + << response->ToString(); |
| return false; |
| + } |
| if (ret != 0) |
| LOG(ERROR) << "Bad return code " << ret << " from KWallet removeEntry"; |
| return ret == 0; |
| @@ -445,26 +603,28 @@ |
| 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. |
| + dbus::MethodCall method_call(kKWalletInterface, "writeEntry"); |
| + dbus::MessageWriter builder(&method_call); |
| + builder.AppendInt32(wallet_handle); // handle |
| + builder.AppendString(folder_name_); // folder |
| + builder.AppendString(signon_realm); // key |
| + builder.AppendArrayOfBytes(static_cast<const uint8_t*>(value.data()), |
| + value.size()); // value |
| + builder.AppendString(app_name_); // appid |
| + scoped_ptr<dbus::Response> response( |
| + kwallet_proxy_->CallMethodAndBlock( |
| + &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT)); |
| + if (!response.get()) { |
| + LOG(ERROR) << "Error contacting kwalletd (writeEntry)"; |
| + return kInvalidKWalletHandle; |
| + } |
| + dbus::MessageReader reader(response.get()); |
| int ret = 0; |
| - dbus_g_proxy_call(proxy_, "writeEntry", &error_, |
| - G_TYPE_INT, wallet_handle, // handle |
| - G_TYPE_STRING, folder_name_.c_str(), // folder |
| - G_TYPE_STRING, signon_realm.c_str(), // key |
| - DBUS_TYPE_G_UCHAR_ARRAY, byte_array, // value |
| - G_TYPE_STRING, app_name_.c_str(), // appid |
| - G_TYPE_INVALID, |
| - G_TYPE_INT, &ret, |
| - G_TYPE_INVALID); |
| - g_array_free(byte_array, true); |
| - |
| - if (CheckError()) |
| + if (!reader.PopInt32(&ret)) { |
| + LOG(ERROR) << "Error reading response from kwalletd (writeEntry): " |
| + << response->ToString(); |
| return false; |
| + } |
| if (ret != 0) |
| LOG(ERROR) << "Bad return code " << ret << " from KWallet writeEntry"; |
| return ret == 0; |
| @@ -505,19 +665,20 @@ |
| } |
| } |
| -bool NativeBackendKWallet::CheckSerializedValue(const GArray* byte_array, |
| - const char* realm) { |
| +bool NativeBackendKWallet::CheckSerializedValue(const uint8_t* byte_array, |
| + size_t length, |
| + const std::string& realm) { |
| const Pickle::Header* header = |
| - reinterpret_cast<const Pickle::Header*>(byte_array->data); |
| - if (byte_array->len < sizeof(*header) || |
| - header->payload_size > byte_array->len - sizeof(*header)) { |
| + reinterpret_cast<const Pickle::Header*>(byte_array); |
| + if (length < sizeof(*header) || |
| + header->payload_size > length - sizeof(*header)) { |
| LOG(WARNING) << "Invalid KWallet entry detected (realm: " << realm << ")"; |
| return false; |
| } |
| return true; |
| } |
| -void NativeBackendKWallet::DeserializeValue(const string& signon_realm, |
| +void NativeBackendKWallet::DeserializeValue(const std::string& signon_realm, |
| const Pickle& pickle, |
| PasswordFormList* forms) { |
| void* iter = NULL; |
| @@ -579,7 +740,7 @@ |
| bool NativeBackendKWallet::ReadGURL(const Pickle& pickle, void** iter, |
| GURL* url) { |
| - string url_string; |
| + std::string url_string; |
| if (!pickle.ReadString(iter, &url_string)) { |
| LOG(ERROR) << "Failed to deserialize URL"; |
| *url = GURL(); |
| @@ -589,55 +750,85 @@ |
| return true; |
| } |
| -bool NativeBackendKWallet::CheckError() { |
| - if (error_) { |
| - LOG(ERROR) << "Failed to complete KWallet call: " << error_->message; |
| - g_error_free(error_); |
| - error_ = NULL; |
| - return true; |
| - } |
| - return false; |
| -} |
| - |
| int NativeBackendKWallet::WalletHandle() { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); |
| + |
| // Open the wallet. |
| // TODO(mdm): Are we leaking these handles? Find out. |
| - 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, app_name_.c_str(), // appid |
| - G_TYPE_INVALID, |
| - G_TYPE_INT, &handle, |
| - G_TYPE_INVALID); |
| - if (CheckError() || handle == kInvalidKWalletHandle) |
| - return kInvalidKWalletHandle; |
| + int32_t handle = kInvalidKWalletHandle; |
| + { |
| + dbus::MethodCall method_call(kKWalletInterface, "open"); |
| + dbus::MessageWriter builder(&method_call); |
| + builder.AppendString(wallet_name_); // wallet |
| + builder.AppendInt64(0); // wid |
| + builder.AppendString(app_name_); // appid |
| + scoped_ptr<dbus::Response> response( |
| + kwallet_proxy_->CallMethodAndBlock( |
| + &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT)); |
| + if (!response.get()) { |
| + LOG(ERROR) << "Error contacting kwalletd (open)"; |
| + return kInvalidKWalletHandle; |
| + } |
| + dbus::MessageReader reader(response.get()); |
| + if (!reader.PopInt32(&handle)) { |
| + LOG(ERROR) << "Error reading response from kwalletd (open): " |
| + << response->ToString(); |
| + return kInvalidKWalletHandle; |
| + } |
| + if (handle == kInvalidKWalletHandle) { |
| + LOG(ERROR) << "Error obtaining KWallet handle"; |
| + 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, folder_name_.c_str(), // folder |
| - G_TYPE_STRING, app_name_.c_str(), // appid |
| - G_TYPE_INVALID, |
| - G_TYPE_BOOLEAN, &has_folder, |
| - G_TYPE_INVALID); |
| - if (CheckError()) |
| - return kInvalidKWalletHandle; |
| + bool has_folder = false; |
| + { |
| + dbus::MethodCall method_call(kKWalletInterface, "hasFolder"); |
| + dbus::MessageWriter builder(&method_call); |
| + builder.AppendInt32(handle); // handle |
| + builder.AppendString(folder_name_); // folder |
| + builder.AppendString(app_name_); // appid |
| + scoped_ptr<dbus::Response> response( |
| + kwallet_proxy_->CallMethodAndBlock( |
| + &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT)); |
| + if (!response.get()) { |
| + LOG(ERROR) << "Error contacting kwalletd (hasFolder)"; |
| + return kInvalidKWalletHandle; |
| + } |
| + dbus::MessageReader reader(response.get()); |
| + if (!reader.PopBool(&has_folder)) { |
| + LOG(ERROR) << "Error reading response from kwalletd (hasFolder): " |
| + << response->ToString(); |
| + 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, folder_name_.c_str(), // folder |
| - G_TYPE_STRING, app_name_.c_str(), // appid |
| - G_TYPE_INVALID, |
| - G_TYPE_BOOLEAN, &success, |
| - G_TYPE_INVALID); |
| - if (CheckError() || !success) |
| + dbus::MethodCall method_call(kKWalletInterface, "createFolder"); |
| + dbus::MessageWriter builder(&method_call); |
| + builder.AppendInt32(handle); // handle |
| + builder.AppendString(folder_name_); // folder |
| + builder.AppendString(app_name_); // appid |
| + scoped_ptr<dbus::Response> response( |
| + kwallet_proxy_->CallMethodAndBlock( |
| + &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT)); |
| + if (!response.get()) { |
| + LOG(ERROR) << "Error contacting kwalletd (createFolder)"; |
| return kInvalidKWalletHandle; |
| + } |
| + dbus::MessageReader reader(response.get()); |
| + bool success = false; |
| + if (!reader.PopBool(&success)) { |
| + LOG(ERROR) << "Error reading response from kwalletd (createFolder): " |
| + << response->ToString(); |
| + return kInvalidKWalletHandle; |
| + } |
| + if (!success) { |
| + LOG(ERROR) << "Error creating KWallet folder"; |
| + return kInvalidKWalletHandle; |
| + } |
| } |
| // Successful initialization. Try migration if necessary. |