blob: eb057e63e7e4a622bb9889264abc60bf77d71a0b [file] [log] [blame]
// Copyright 2016 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 <components/os_crypt/kwallet_dbus.h>
#include <algorithm>
#include <memory>
#include "base/logging.h"
#include "dbus/bus.h"
#include "dbus/message.h"
#include "dbus/object_proxy.h"
namespace {
// DBus service, path, and interface names for klauncher and kwalletd.
const char kKWalletDName[] = "kwalletd";
const char kKWalletD5Name[] = "kwalletd5";
const char kKWalletServiceName[] = "org.kde.kwalletd";
const char kKWallet5ServiceName[] = "org.kde.kwalletd5";
const char kKWalletPath[] = "/modules/kwalletd";
const char kKWallet5Path[] = "/modules/kwalletd5";
const char kKWalletInterface[] = "org.kde.KWallet";
const char kKLauncherServiceName[] = "org.kde.klauncher";
const char kKLauncherPath[] = "/KLauncher";
const char kKLauncherInterface[] = "org.kde.KLauncher";
} // namespace
KWalletDBus::KWalletDBus(base::nix::DesktopEnvironment desktop_env)
: session_bus_(nullptr), kwallet_proxy_(nullptr) {
if (desktop_env == base::nix::DESKTOP_ENVIRONMENT_KDE5) {
dbus_service_name_ = kKWallet5ServiceName;
dbus_path_ = kKWallet5Path;
kwalletd_name_ = kKWalletD5Name;
} else {
dbus_service_name_ = kKWalletServiceName;
dbus_path_ = kKWalletPath;
kwalletd_name_ = kKWalletDName;
}
}
KWalletDBus::~KWalletDBus() = default;
dbus::Bus* KWalletDBus::GetSessionBus() {
return session_bus_.get();
}
void KWalletDBus::SetSessionBus(scoped_refptr<dbus::Bus> session_bus) {
session_bus_ = session_bus;
kwallet_proxy_ = session_bus_->GetObjectProxy(dbus_service_name_,
dbus::ObjectPath(dbus_path_));
}
bool KWalletDBus::StartKWalletd() {
dbus::ObjectProxy* klauncher = session_bus_->GetObjectProxy(
kKLauncherServiceName, dbus::ObjectPath(kKLauncherPath));
dbus::MethodCall method_call(kKLauncherInterface,
"start_service_by_desktop_name");
dbus::MessageWriter builder(&method_call);
std::vector<std::string> empty;
builder.AppendString(kwalletd_name_); // serviceName
builder.AppendArrayOfStrings(empty); // urls
builder.AppendArrayOfStrings(empty); // envs
builder.AppendString(std::string()); // startup_id
builder.AppendBool(false); // blind
std::unique_ptr<dbus::Response> response(klauncher->CallMethodAndBlock(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
if (!response) {
LOG(ERROR) << "Error contacting klauncher to start " << kwalletd_name_;
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_name_ << ": " << response->ToString();
return false;
}
if (!error.empty() || ret) {
LOG(ERROR) << "Error launching " << kwalletd_name_ << ": error '" << error
<< "' (code " << ret << ")";
return false;
}
return true;
}
KWalletDBus::Error KWalletDBus::IsEnabled(bool* enabled) {
dbus::MethodCall method_call(kKWalletInterface, "isEnabled");
std::unique_ptr<dbus::Response> response(kwallet_proxy_->CallMethodAndBlock(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
if (!response) {
LOG(ERROR) << "Error contacting " << kwalletd_name_ << " (isEnabled)";
return CANNOT_CONTACT;
}
dbus::MessageReader reader(response.get());
if (!reader.PopBool(enabled)) {
LOG(ERROR) << "Error reading response from " << kwalletd_name_
<< " (isEnabled): " << response->ToString();
return CANNOT_READ;
}
// Not enabled? Don't use KWallet. But also don't warn here.
if (!enabled) {
VLOG(1) << kwalletd_name_ << " reports that KWallet is not enabled.";
}
return SUCCESS;
}
KWalletDBus::Error KWalletDBus::NetworkWallet(std::string* wallet_name) {
// Get the wallet name.
dbus::MethodCall method_call(kKWalletInterface, "networkWallet");
std::unique_ptr<dbus::Response> response(kwallet_proxy_->CallMethodAndBlock(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
if (!response) {
LOG(ERROR) << "Error contacting " << kwalletd_name_ << " (networkWallet)";
return CANNOT_CONTACT;
}
dbus::MessageReader reader(response.get());
if (!reader.PopString(wallet_name)) {
LOG(ERROR) << "Error reading response from " << kwalletd_name_
<< " (networkWallet): " << response->ToString();
return CANNOT_READ;
}
return SUCCESS;
}
KWalletDBus::Error KWalletDBus::Open(const std::string& wallet_name,
const std::string& app_name,
int* handle_ptr) {
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
std::unique_ptr<dbus::Response> response(kwallet_proxy_->CallMethodAndBlock(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
if (!response) {
LOG(ERROR) << "Error contacting " << kwalletd_name_ << " (open)";
return CANNOT_CONTACT;
}
dbus::MessageReader reader(response.get());
if (!reader.PopInt32(handle_ptr)) {
LOG(ERROR) << "Error reading response from " << kwalletd_name_
<< " (open): " << response->ToString();
return CANNOT_READ;
}
return SUCCESS;
}
KWalletDBus::Error KWalletDBus::HasEntry(const int wallet_handle,
const std::string& folder_name,
const std::string& signon_realm,
const std::string& app_name,
bool* has_entry) {
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
std::unique_ptr<dbus::Response> response(kwallet_proxy_->CallMethodAndBlock(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
if (!response) {
LOG(ERROR) << "Error contacting " << kwalletd_name_ << " (hasEntry)";
return CANNOT_CONTACT;
}
dbus::MessageReader reader(response.get());
if (!reader.PopBool(has_entry)) {
LOG(ERROR) << "Error reading response from " << kwalletd_name_
<< " (hasEntry): " << response->ToString();
return CANNOT_READ;
}
return SUCCESS;
}
KWalletDBus::Error KWalletDBus::ReadEntry(const int wallet_handle,
const std::string& folder_name,
const std::string& signon_realm,
const std::string& app_name,
std::vector<uint8_t>* bytes_ptr) {
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
std::unique_ptr<dbus::Response> response(kwallet_proxy_->CallMethodAndBlock(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
if (!response) {
LOG(ERROR) << "Error contacting " << kwalletd_name_ << " (readEntry)";
return CANNOT_CONTACT;
}
size_t length = 0;
const uint8_t* bytes_temp = nullptr;
dbus::MessageReader reader(response.get());
if (!reader.PopArrayOfBytes(&bytes_temp, &length)) {
LOG(ERROR) << "Error reading response from " << kwalletd_name_
<< " (readEntry): " << response->ToString();
return CANNOT_READ;
}
if (bytes_temp) {
bytes_ptr->assign(bytes_temp, bytes_temp + length);
} else {
bytes_ptr->clear();
}
return SUCCESS;
}
KWalletDBus::Error KWalletDBus::EntryList(
const int wallet_handle,
const std::string& folder_name,
const std::string& app_name,
std::vector<std::string>* entry_list_ptr) {
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
std::unique_ptr<dbus::Response> response(kwallet_proxy_->CallMethodAndBlock(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
if (!response) {
LOG(ERROR) << "Error contacting " << kwalletd_name_ << " (entryList)";
return CANNOT_CONTACT;
}
dbus::MessageReader reader(response.get());
if (!reader.PopArrayOfStrings(entry_list_ptr)) {
LOG(ERROR) << "Error reading response from " << kwalletd_name_
<< "(entryList): " << response->ToString();
return CANNOT_READ;
}
return SUCCESS;
}
KWalletDBus::Error KWalletDBus::RemoveEntry(const int wallet_handle,
const std::string& folder_name,
const std::string& signon_realm,
const std::string& app_name,
int* return_code_ptr) {
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
std::unique_ptr<dbus::Response> response(kwallet_proxy_->CallMethodAndBlock(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
if (!response) {
LOG(ERROR) << "Error contacting " << kwalletd_name_ << " (removeEntry)";
return CANNOT_CONTACT;
}
dbus::MessageReader reader(response.get());
if (!reader.PopInt32(return_code_ptr)) {
LOG(ERROR) << "Error reading response from " << kwalletd_name_
<< " (removeEntry): " << response->ToString();
return CANNOT_READ;
}
return SUCCESS;
}
KWalletDBus::Error KWalletDBus::WriteEntry(const int wallet_handle,
const std::string& folder_name,
const std::string& signon_realm,
const std::string& app_name,
const uint8_t* data,
const size_t length,
int* return_code_ptr) {
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(data, length); // value
builder.AppendString(app_name); // appid
std::unique_ptr<dbus::Response> response(kwallet_proxy_->CallMethodAndBlock(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
if (!response) {
LOG(ERROR) << "Error contacting " << kwalletd_name_ << " (writeEntry)";
return CANNOT_CONTACT;
}
dbus::MessageReader reader(response.get());
if (!reader.PopInt32(return_code_ptr)) {
LOG(ERROR) << "Error reading response from " << kwalletd_name_
<< " (writeEntry): " << response->ToString();
return CANNOT_READ;
}
return SUCCESS;
}
KWalletDBus::Error KWalletDBus::HasFolder(const int handle,
const std::string& folder_name,
const std::string& app_name,
bool* has_folder_ptr) {
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
std::unique_ptr<dbus::Response> response(kwallet_proxy_->CallMethodAndBlock(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
if (!response) {
LOG(ERROR) << "Error contacting " << kwalletd_name_ << " (hasFolder)";
return CANNOT_CONTACT;
}
dbus::MessageReader reader(response.get());
if (!reader.PopBool(has_folder_ptr)) {
LOG(ERROR) << "Error reading response from " << kwalletd_name_
<< " (hasFolder): " << response->ToString();
return CANNOT_READ;
}
return SUCCESS;
}
KWalletDBus::Error KWalletDBus::CreateFolder(const int handle,
const std::string& folder_name,
const std::string& app_name,
bool* success_ptr) {
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
std::unique_ptr<dbus::Response> response(kwallet_proxy_->CallMethodAndBlock(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
if (!response) {
LOG(ERROR) << "Error contacting " << kwalletd_name_ << " (createFolder)";
return CANNOT_CONTACT;
}
dbus::MessageReader reader(response.get());
if (!reader.PopBool(success_ptr)) {
LOG(ERROR) << "Error reading response from " << kwalletd_name_
<< " (createFolder): " << response->ToString();
return CANNOT_READ;
}
return SUCCESS;
}
KWalletDBus::Error KWalletDBus::WritePassword(const int handle,
const std::string& folder_name,
const std::string& key,
const std::string& password,
const std::string& app_name,
bool* const write_success_ptr) {
dbus::MethodCall method_call(kKWalletInterface, "writePassword");
dbus::MessageWriter builder(&method_call);
builder.AppendInt32(handle);
builder.AppendString(folder_name);
builder.AppendString(key);
builder.AppendString(password);
builder.AppendString(app_name);
std::unique_ptr<dbus::Response> response(kwallet_proxy_->CallMethodAndBlock(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
if (!response) {
LOG(ERROR) << "Error contacting " << kwalletd_name_ << " (writePassword)";
return CANNOT_CONTACT;
}
dbus::MessageReader reader(response.get());
int return_code;
if (!reader.PopInt32(&return_code)) {
LOG(ERROR) << "Error reading response from " << kwalletd_name_
<< " (writePassword): " << response->ToString();
return CANNOT_READ;
}
*write_success_ptr = return_code == 0;
return SUCCESS;
}
KWalletDBus::Error KWalletDBus::ReadPassword(const int handle,
const std::string& folder_name,
const std::string& key,
const std::string& app_name,
std::string* const password_ptr) {
dbus::MethodCall method_call(kKWalletInterface, "readPassword");
dbus::MessageWriter builder(&method_call);
builder.AppendInt32(handle);
builder.AppendString(folder_name);
builder.AppendString(key);
builder.AppendString(app_name);
std::unique_ptr<dbus::Response> response(kwallet_proxy_->CallMethodAndBlock(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
if (!response) {
LOG(ERROR) << "Error contacting " << kwalletd_name_ << " (readPassword)";
return CANNOT_CONTACT;
}
dbus::MessageReader reader(response.get());
if (!reader.PopString(password_ptr)) {
LOG(ERROR) << "Error reading response from " << kwalletd_name_
<< " (readPassword): " << response->ToString();
return CANNOT_READ;
}
return SUCCESS;
}
KWalletDBus::Error KWalletDBus::Close(const int handle,
const bool force,
const std::string& app_name,
bool* success_ptr) {
dbus::MethodCall method_call(kKWalletInterface, "close");
dbus::MessageWriter builder(&method_call);
builder.AppendInt32(handle);
builder.AppendBool(force);
builder.AppendString(app_name);
std::unique_ptr<dbus::Response> response(kwallet_proxy_->CallMethodAndBlock(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
if (!response) {
LOG(ERROR) << "Error contacting " << kwalletd_name_ << " (close)";
return CANNOT_CONTACT;
}
dbus::MessageReader reader(response.get());
int return_code = 1;
if (!reader.PopInt32(&return_code)) {
LOG(ERROR) << "Error reading response from " << kwalletd_name_
<< " (close): " << response->ToString();
return CANNOT_READ;
}
*success_ptr = return_code == 0;
return SUCCESS;
}