// 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 #include #include #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 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 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 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 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 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 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 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* 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 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* 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 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 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 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 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 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 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, base::Optional* 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 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()); std::string password; if (!reader.PopString(&password)) { LOG(ERROR) << "Error reading response from " << kwalletd_name_ << " (readPassword): " << response->ToString(); *password_ptr = base::nullopt; return CANNOT_READ; } *password_ptr = std::move(password); 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 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; }