/* This file is part of the KDE project * * Copyright (C) 2002-2004 George Staikos * Copyright (C) 2008 Michael Leupold * Copyright (C) 2011 Valentin Rusu * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "kwallet.h" #include "config-kwallet.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_KSECRETSSERVICE #include "ksecretsservice/ksecretsservicecollection.h" #endif #include "kwallet_interface.h" #ifdef HAVE_KSECRETSSERVICE typedef QMap StringToStringStringMapMap; Q_DECLARE_METATYPE(StringToStringStringMapMap) #endif typedef QMap StringByteArrayMap; Q_DECLARE_METATYPE(StringByteArrayMap) namespace KWallet { class KWalletDLauncher { public: KWalletDLauncher(); ~KWalletDLauncher(); org::kde::KWallet &getInterface(); // this static variable is used below to switch between old KWallet // infrastructure and the new one which is built on top of the new // KSecretsService infrastructure. It's value can be changed via the // the Wallet configuration module in System Settings bool m_useKSecretsService; org::kde::KWallet *m_wallet; KConfigGroup m_cgroup; }; K_GLOBAL_STATIC(KWalletDLauncher, walletLauncher) static QString appid() { if (KGlobal::hasMainComponent()) { KComponentData cData = KGlobal::mainComponent(); if (cData.isValid()) { const KAboutData* aboutData = cData.aboutData(); if (aboutData) { return aboutData->programName(); } return cData.componentName(); } } return qApp->applicationName(); } static void registerTypes() { static bool registered = false; if (!registered) { #ifdef HAVE_KSECRETSSERVICE qDBusRegisterMetaType(); qDBusRegisterMetaType(); #endif qDBusRegisterMetaType(); registered = true; } } bool Wallet::isUsingKSecretsService() { return walletLauncher->m_useKSecretsService; } const QString Wallet::LocalWallet() { // NOTE: This method stays unchanged for KSecretsService KConfigGroup cfg(KSharedConfig::openConfig("kwalletrc")->group("Wallet")); if (!cfg.readEntry("Use One Wallet", true)) { QString tmp = cfg.readEntry("Local Wallet", "localwallet"); if (tmp.isEmpty()) { return "localwallet"; } return tmp; } QString tmp = cfg.readEntry("Default Wallet", "kdewallet"); if (tmp.isEmpty()) { return "kdewallet"; } return tmp; } const QString Wallet::NetworkWallet() { // NOTE: This method stays unchanged for KSecretsService KConfigGroup cfg(KSharedConfig::openConfig("kwalletrc")->group("Wallet")); QString tmp = cfg.readEntry("Default Wallet", "kdewallet"); if (tmp.isEmpty()) { return "kdewallet"; } return tmp; } const QString Wallet::PasswordFolder() { return "Passwords"; } const QString Wallet::FormDataFolder() { return "Form Data"; } class Wallet::WalletPrivate { public: WalletPrivate(Wallet *wallet, int h, const QString &n) : q(wallet), name(n), handle(h) #ifdef HAVE_KSECRETSSERVICE , secretsCollection(0) #endif {} void walletServiceUnregistered(); #ifdef HAVE_KSECRETSSERVICE template int writeEntry( const QString& key, const T &value, Wallet::EntryType entryType ) { int rc = -1; KSecretsService::Secret secret; secret.setValue( QVariant::fromValue(value) ); KSecretsService::StringStringMap attrs; attrs[KSS_ATTR_ENTRYFOLDER] = folder; attrs[KSS_ATTR_WALLETTYPE] = QString("%1").arg((int)entryType); KSecretsService::CreateCollectionItemJob *createItemJob = secretsCollection->createItem( key, attrs, secret ); if ( !createItemJob->exec() ) { kDebug(285) << "Cannot execute CreateCollectionItemJob : " << createItemJob->errorString(); } rc = createItemJob->error(); return rc; } QExplicitlySharedDataPointer findItem( const QString& key ) const; template int readEntry( const QString& key, T& value ) const; bool readSecret( const QString& key, KSecretsService::Secret& value ) const; template int forEachItemThatMatches( const QString &key, V verb ) { int rc = -1; KSecretsService::StringStringMap attrs; attrs[KSS_ATTR_ENTRYFOLDER] = folder; KSecretsService::SearchCollectionItemsJob *searchItemsJob = secretsCollection->searchItems(attrs); if ( searchItemsJob->exec() ) { QRegExp re(key, Qt::CaseSensitive, QRegExp::Wildcard); foreach( KSecretsService::SearchCollectionItemsJob::Item item , searchItemsJob->items() ) { KSecretsService::ReadItemPropertyJob *readLabelJob = item->label(); if ( readLabelJob->exec() ) { QString label = readLabelJob->propertyValue().toString(); if ( re.exactMatch( label ) ) { if ( verb( this, label, item.data() ) ) { rc = 0; // one successfull iteration already produced results, so success return } } } else { kDebug(285) << "Cannot execute ReadItemPropertyJob " << readLabelJob->errorString(); } } } else { kDebug(285) << "Cannot execute KSecretsService::SearchCollectionItemsJob " << searchItemsJob->errorString(); } return rc; } void createDefaultFolders(); struct InsertIntoEntryList; struct InsertIntoMapList; struct InsertIntoPasswordList; KSecretsService::Collection *secretsCollection; #endif // HAVE_KSECRETSSERVICE Wallet *q; QString name; QString folder; int handle; int transactionId; }; #ifdef HAVE_KSECRETSSERVICE void Wallet::WalletPrivate::createDefaultFolders() { // NOTE: KWalletManager expects newly created wallets to have two default folders // b->createFolder(KWallet::Wallet::PasswordFolder()); // b->createFolder(KWallet::Wallet::FormDataFolder()); QString strDummy(""); folder = PasswordFolder(); writeEntry( PasswordFolder(), strDummy, KWallet::Wallet::Unknown ); folder = FormDataFolder(); writeEntry( FormDataFolder(), strDummy, KWallet::Wallet::Unknown ); } #endif // HAVE_KSECRETSSERVICE static const char s_kwalletdServiceName[] = "org.kde.kwalletd"; Wallet::Wallet(int handle, const QString& name) : QObject(0L), d(new WalletPrivate(this, handle, name)) { if (walletLauncher->m_useKSecretsService) { // see openWallet for initialization code; this constructor does not have any code } else { QDBusServiceWatcher *watcher = new QDBusServiceWatcher(QString::fromLatin1(s_kwalletdServiceName), QDBusConnection::sessionBus(), QDBusServiceWatcher::WatchForUnregistration, this); connect(watcher, SIGNAL(serviceUnregistered(QString)), this, SLOT(walletServiceUnregistered())); connect(&walletLauncher->getInterface(), SIGNAL(walletClosed(int)), SLOT(slotWalletClosed(int))); connect(&walletLauncher->getInterface(), SIGNAL(folderListUpdated(QString)), SLOT(slotFolderListUpdated(QString))); connect(&walletLauncher->getInterface(), SIGNAL(folderUpdated(QString,QString)), SLOT(slotFolderUpdated(QString,QString))); connect(&walletLauncher->getInterface(), SIGNAL(applicationDisconnected(QString,QString)), SLOT(slotApplicationDisconnected(QString,QString))); // Verify that the wallet is still open if (d->handle != -1) { QDBusReply r = walletLauncher->getInterface().isOpen(d->handle); if (r.isValid() && !r) { d->handle = -1; d->name.clear(); } } } } Wallet::~Wallet() { #ifdef HAVE_KSECRETSSERVICE if (walletLauncher->m_useKSecretsService) { d->folder.clear(); d->name.clear(); delete d->secretsCollection; } else { #endif if (d->handle != -1) { if (!walletLauncher.isDestroyed()) { walletLauncher->getInterface().close(d->handle, false, appid()); } else { kDebug(285) << "Problem with static destruction sequence." "Destroy any static Wallet before the event-loop exits."; } d->handle = -1; d->folder.clear(); d->name.clear(); } #ifdef HAVE_KSECRETSSERVICE } #endif delete d; } QStringList Wallet::walletList() { QStringList result; #ifdef HAVE_KSECRETSSERVICE if (walletLauncher->m_useKSecretsService) { KSecretsService::ListCollectionsJob *listJob = KSecretsService::Collection::listCollections(); if ( listJob->exec() ) { result = listJob->collections(); } else { kDebug(285) << "Cannot execute ListCollectionsJob: " << listJob->errorString(); } } else { #endif QDBusReply r = walletLauncher->getInterface().wallets(); if (!r.isValid()) { kDebug(285) << "Invalid DBus reply: " << r.error(); } else result = r; #ifdef HAVE_KSECRETSSERVICE } #endif return result; } void Wallet::changePassword(const QString& name, WId w) { if( w == 0 ) kDebug(285) << "Pass a valid window to KWallet::Wallet::changePassword()."; // Make sure the password prompt window will be visible and activated KWindowSystem::allowExternalProcessWindowActivation(); #ifdef HAVE_KSECRETSSERVICE if (walletLauncher->m_useKSecretsService) { KSecretsService::Collection *coll = KSecretsService::Collection::findCollection( name ); KSecretsService::ChangeCollectionPasswordJob* changePwdJob = coll->changePassword(); if ( !changePwdJob->exec() ) { kDebug(285) << "Cannot execute change password job: " << changePwdJob->errorString(); } coll->deleteLater(); } else { #endif walletLauncher->getInterface().changePassword(name, (qlonglong)w, appid()); #ifdef HAVE_KSECRETSSERVICE } #endif } bool Wallet::isEnabled() { #ifdef HAVE_KSECRETSSERVICE if (walletLauncher->m_useKSecretsService) { return walletLauncher->m_cgroup.readEntry("Enabled", true); } else { #endif QDBusReply r = walletLauncher->getInterface().isEnabled(); if (!r.isValid()) { kDebug(285) << "Invalid DBus reply: " << r.error(); return false; } else return r; #ifdef HAVE_KSECRETSSERVICE } #endif } bool Wallet::isOpen(const QString& name) { #ifdef HAVE_KSECRETSSERVICE if (walletLauncher->m_useKSecretsService) { KSecretsService::Collection *coll = KSecretsService::Collection::findCollection( name, KSecretsService::Collection::OpenOnly ); KSecretsService::ReadCollectionPropertyJob *readLocked = coll->isLocked(); if ( readLocked->exec() ) { return !readLocked->propertyValue().toBool(); } else { kDebug() << "ReadLocked job failed"; return false; } } else { #endif QDBusReply r = walletLauncher->getInterface().isOpen(name); if (!r.isValid()) { kDebug(285) << "Invalid DBus reply: " << r.error(); return false; } else return r; #ifdef HAVE_KSECRETSSERVICE } #endif } int Wallet::closeWallet(const QString& name, bool force) { #ifdef HAVE_KSECRETSSERVICE if (walletLauncher->m_useKSecretsService) { kDebug(285) << "Wallet::closeWallet NOOP"; return 0; } else { #endif QDBusReply r = walletLauncher->getInterface().close(name, force); if (!r.isValid()) { kDebug(285) << "Invalid DBus reply: " << r.error(); return -1; } else return r; #ifdef HAVE_KSECRETSSERVICE } #endif } int Wallet::deleteWallet(const QString& name) { #ifdef HAVE_KSECRETSSERVICE if (walletLauncher->m_useKSecretsService) { KSecretsService::Collection *coll = KSecretsService::Collection::findCollection(name, KSecretsService::Collection::OpenOnly); KJob *deleteJob = coll->deleteCollection(); if (!deleteJob->exec()) { kDebug(285) << "Cannot execute delete job " << deleteJob->errorString(); } return deleteJob->error(); } else { #endif QDBusReply r = walletLauncher->getInterface().deleteWallet(name); if (!r.isValid()) { kDebug(285) << "Invalid DBus reply: " << r.error(); return -1; } else return r; #ifdef HAVE_KSECRETSSERVICE } #endif } Wallet *Wallet::openWallet(const QString& name, WId w, OpenType ot) { if( w == 0 ) kDebug(285) << "Pass a valid window to KWallet::Wallet::openWallet()."; #ifdef HAVE_KSECRETSSERVICE if (walletLauncher->m_useKSecretsService) { Wallet *wallet = new Wallet(-1, name); // FIXME: should we specify CreateCollection or OpenOnly here? wallet->d->secretsCollection = KSecretsService::Collection::findCollection(name, KSecretsService::Collection::CreateCollection, QVariantMap(), w); connect( wallet->d->secretsCollection, SIGNAL(statusChanged(int)), wallet, SLOT(slotCollectionStatusChanged(int)) ); connect( wallet->d->secretsCollection, SIGNAL(deleted()), wallet, SLOT(slotCollectionDeleted()) ); if ( ot == Synchronous ) { kDebug() << "WARNING openWallet OpenType=Synchronous requested"; // TODO: not sure what to do with in this case; however, all other KSecretsService API methods are already // async and will perform sync inside this API because of it's design } return wallet; } else { #endif Wallet *wallet = new Wallet(-1, name); // connect the daemon's opened signal to the slot filtering the // signals we need connect(&walletLauncher->getInterface(), SIGNAL(walletAsyncOpened(int,int)), wallet, SLOT(walletAsyncOpened(int,int))); // Make sure the password prompt window will be visible and activated KWindowSystem::allowExternalProcessWindowActivation(); // do the call QDBusReply r; if (ot == Synchronous) { r = walletLauncher->getInterface().open(name, (qlonglong)w, appid()); // after this call, r would contain a transaction id >0 if OK or -1 if NOK // if OK, the slot walletAsyncOpened should have been received, but the transaction id // will not match. We'll get that handle from the reply - see below } else if (ot == Asynchronous) { r = walletLauncher->getInterface().openAsync(name, (qlonglong)w, appid(), true); } else if (ot == Path) { r = walletLauncher->getInterface().openPathAsync(name, (qlonglong)w, appid(), true); } else { delete wallet; return 0; } // error communicating with the daemon (maybe not running) if (!r.isValid()) { kDebug(285) << "Invalid DBus reply: " << r.error(); delete wallet; return 0; } wallet->d->transactionId = r.value(); if (ot == Synchronous || ot == Path) { // check for an immediate error if (wallet->d->transactionId < 0) { delete wallet; wallet = 0; } else { wallet->d->handle = r.value(); } } else if (ot == Asynchronous) { if (wallet->d->transactionId < 0) { QTimer::singleShot(0, wallet, SLOT(emitWalletAsyncOpenError())); // client code is responsible for deleting the wallet } } return wallet; #ifdef HAVE_KSECRETSSERVICE } #endif } void Wallet::slotCollectionStatusChanged(int status) { #ifdef HAVE_KSECRETSSERVICE KSecretsService::Collection::Status collStatus = (KSecretsService::Collection::Status)status; switch ( collStatus ) { case KSecretsService::Collection::NewlyCreated: d->createDefaultFolders(); // fall through case KSecretsService::Collection::FoundExisting: emitWalletOpened(); break; case KSecretsService::Collection::Deleted: case KSecretsService::Collection::Invalid: case KSecretsService::Collection::Pending: // nothing to do break; case KSecretsService::Collection::NotFound: emitWalletAsyncOpenError(); break; } #endif } void Wallet::slotCollectionDeleted() { d->folder.clear(); d->name.clear(); emit walletClosed(); } bool Wallet::disconnectApplication(const QString& wallet, const QString& app) { #ifdef HAVE_KSECRETSSERVICE if (walletLauncher->m_useKSecretsService) { kDebug() << "Wallet::disconnectApplication NOOP"; return true; } else { #endif QDBusReply r = walletLauncher->getInterface().disconnectApplication(wallet, app); if (!r.isValid()) { kDebug(285) << "Invalid DBus reply: " << r.error(); return false; } else return r; #ifdef HAVE_KSECRETSSERVICE } #endif } QStringList Wallet::users(const QString& name) { #ifdef HAVE_KSECRETSSERVICE if (walletLauncher->m_useKSecretsService) { kDebug() << "KSecretsService does not handle users list"; return QStringList(); } else { #endif QDBusReply r = walletLauncher->getInterface().users(name); if (!r.isValid()) { kDebug(285) << "Invalid DBus reply: " << r.error(); return QStringList(); } else return r; #ifdef HAVE_KSECRETSSERVICE } #endif } int Wallet::sync() { #ifdef HAVE_KSECRETSSERVICE if (walletLauncher->m_useKSecretsService) { // NOOP with KSecretsService } else { #endif if (d->handle == -1) { return -1; } walletLauncher->getInterface().sync(d->handle, appid()); #ifdef HAVE_KSECRETSSERVICE } #endif return 0; } int Wallet::lockWallet() { #ifdef HAVE_KSECRETSSERVICE if (walletLauncher->m_useKSecretsService) { KSecretsService::CollectionLockJob *lockJob = d->secretsCollection->lock(); if (lockJob->exec()) { d->folder.clear(); d->name.clear(); } else { kDebug(285) << "Cannot execute KSecretsService::CollectionLockJob : " << lockJob->errorString(); return -1; } return lockJob->error(); } else { #endif if (d->handle == -1) { return -1; } QDBusReply r = walletLauncher->getInterface().close(d->handle, true, appid()); d->handle = -1; d->folder.clear(); d->name.clear(); if (r.isValid()) { return r; } else { kDebug(285) << "Invalid DBus reply: " << r.error(); return -1; } #ifdef HAVE_KSECRETSSERVICE } #endif } const QString& Wallet::walletName() const { return d->name; } bool Wallet::isOpen() const { #ifdef HAVE_KSECRETSSERVICE if (walletLauncher->m_useKSecretsService) { return !d->secretsCollection->isLocked(); } else { #endif return d->handle != -1; #ifdef HAVE_KSECRETSSERVICE } #endif } void Wallet::requestChangePassword(WId w) { if( w == 0 ) kDebug(285) << "Pass a valid window to KWallet::Wallet::requestChangePassword()."; #ifdef HAVE_KSECRETSSERVICE if (walletLauncher->m_useKSecretsService) { KSecretsService::ChangeCollectionPasswordJob *changePwdJob = d->secretsCollection->changePassword(); if (!changePwdJob->exec()) { kDebug(285) << "Cannot execute ChangeCollectionPasswordJob : " << changePwdJob->errorString(); } } else { #endif if (d->handle == -1) { return; } // Make sure the password prompt window will be visible and activated KWindowSystem::allowExternalProcessWindowActivation(); walletLauncher->getInterface().changePassword(d->name, (qlonglong)w, appid()); #ifdef HAVE_KSECRETSSERVICE } #endif } void Wallet::slotWalletClosed(int handle) { #ifdef HAVE_KSECRETSSERVICE if (walletLauncher->m_useKSecretsService) { // TODO: implement this Q_ASSERT(0); } else { #endif if (d->handle == handle) { d->handle = -1; d->folder.clear(); d->name.clear(); emit walletClosed(); } #ifdef HAVE_KSECRETSSERVICE } #endif } QStringList Wallet::folderList() { #ifdef HAVE_KSECRETSSERVICE if (walletLauncher->m_useKSecretsService) { QStringList result; KSecretsService::StringStringMap attrs; attrs[KSS_ATTR_ENTRYFOLDER] = ""; // search for items having this attribute no matter what value it has KSecretsService::SearchCollectionItemsJob *searchJob = d->secretsCollection->searchItems(attrs); if (searchJob->exec()) { KSecretsService::ReadCollectionItemsJob::ItemList itemList = searchJob->items(); foreach( const KSecretsService::ReadCollectionItemsJob::Item &item, itemList ) { KSecretsService::ReadItemPropertyJob *readAttrsJob = item->attributes(); if (readAttrsJob->exec()) { KSecretsService::StringStringMap attrs = readAttrsJob->propertyValue().value(); const QString folder = attrs[KSS_ATTR_ENTRYFOLDER]; if (!folder.isEmpty() && !result.contains(folder)) { result.append(folder); } } else { kDebug(285) << "Cannot read item attributes : " << readAttrsJob->errorString(); } } } else { kDebug(285) << "Cannot execute ReadCollectionItemsJob : " << searchJob->errorString(); } return result; } else { #endif if (d->handle == -1) { return QStringList(); } QDBusReply r = walletLauncher->getInterface().folderList(d->handle, appid()); if (!r.isValid()) { kDebug(285) << "Invalid DBus reply: " << r.error(); return QStringList(); } else return r; #ifdef HAVE_KSECRETSSERVICE } #endif } QStringList Wallet::entryList() { #ifdef HAVE_KSECRETSSERVICE if (walletLauncher->m_useKSecretsService) { QStringList result; KSecretsService::StringStringMap attrs; attrs[KSS_ATTR_ENTRYFOLDER] = d->folder; KSecretsService::SearchCollectionItemsJob *readItemsJob = d->secretsCollection->searchItems( attrs ); if ( readItemsJob->exec() ) { foreach( KSecretsService::SearchCollectionItemsJob::Item item, readItemsJob->items() ) { KSecretsService::ReadItemPropertyJob *readLabelJob = item->label(); if ( readLabelJob->exec() ) { result.append( readLabelJob->propertyValue().toString() ); } else { kDebug(285) << "Cannot execute readLabelJob" << readItemsJob->errorString(); } } } else { kDebug(285) << "Cannot execute readItemsJob" << readItemsJob->errorString(); } return result; } else { #endif if (d->handle == -1) { return QStringList(); } QDBusReply r = walletLauncher->getInterface().entryList(d->handle, d->folder, appid()); if (!r.isValid()) { kDebug(285) << "Invalid DBus reply: " << r.error(); return QStringList(); } else return r; #ifdef HAVE_KSECRETSSERVICE } #endif } bool Wallet::hasFolder(const QString& f) { #ifdef HAVE_KSECRETSSERVICE if (walletLauncher->m_useKSecretsService) { // FIXME: well, this is not the best implementation, but it's done quickly :) // the best way would be to searchItems with the attribute label having the value f // doing that would reduce DBus traffic. But KWallet API wille not last. QStringList folders = folderList(); return folders.contains(f); } else { #endif if (d->handle == -1) { return false; } QDBusReply r = walletLauncher->getInterface().hasFolder(d->handle, f, appid()); if (!r.isValid()) { kDebug(285) << "Invalid DBus reply: " << r.error(); return false; } else return r; #ifdef HAVE_KSECRETSSERVICE } #endif } bool Wallet::createFolder(const QString& f) { #ifdef HAVE_KSECRETSSERVICE if (walletLauncher->m_useKSecretsService) { QString strDummy(""); d->folder = f; d->writeEntry( f, strDummy, KWallet::Wallet::Unknown ); return true; } else { #endif if (d->handle == -1) { return false; } if (!hasFolder(f)) { QDBusReply r = walletLauncher->getInterface().createFolder(d->handle, f, appid()); if (!r.isValid()) { kDebug(285) << "Invalid DBus reply: " << r.error(); return false; } else return r; } return true; // folder already exists #ifdef HAVE_KSECRETSSERVICE } #endif } bool Wallet::setFolder(const QString& f) { bool rc = false; #ifdef HAVE_KSECRETSSERVICE if (walletLauncher->m_useKSecretsService) { if (hasFolder(f)) { d->folder = f; rc = true; } } else { #endif if (d->handle == -1) { return rc; } // Don't do this - the folder could have disappeared? #if 0 if (f == d->folder) { return true; } #endif if (hasFolder(f)) { d->folder = f; rc = true; } #ifdef HAVE_KSECRETSSERVICE } #endif return rc; } bool Wallet::removeFolder(const QString& f) { #ifdef HAVE_KSECRETSSERVICE if (walletLauncher->m_useKSecretsService) { bool result = false; // search for all items having the folder f then delete them KSecretsService::StringStringMap attrs; attrs[KSS_ATTR_ENTRYFOLDER] = f; KSecretsService::SearchCollectionItemsJob *searchJob = d->secretsCollection->searchItems(attrs); if (searchJob->exec()) { KSecretsService::SearchCollectionItemsJob::ItemList itemList = searchJob->items(); if ( !itemList.isEmpty() ) { result = true; foreach( const KSecretsService::SearchCollectionItemsJob::Item &item, itemList ) { KSecretsService::SecretItemDeleteJob *deleteJob = item->deleteItem(); if (!deleteJob->exec()) { kDebug(285) << "Cannot delete item : " << deleteJob->errorString(); result = false; } result &= true; } } } else { kDebug(285) << "Cannot execute KSecretsService::SearchCollectionItemsJob : " << searchJob->errorString(); } return result; } else { #endif if (d->handle == -1) { return false; } QDBusReply r = walletLauncher->getInterface().removeFolder(d->handle, f, appid()); if (d->folder == f) { setFolder(QString()); } if (!r.isValid()) { kDebug(285) << "Invalid DBus reply: " << r.error(); return false; } else return r; #ifdef HAVE_KSECRETSSERVICE } #endif } const QString& Wallet::currentFolder() const { return d->folder; } #ifdef HAVE_KSECRETSSERVICE QExplicitlySharedDataPointer Wallet::WalletPrivate::findItem( const QString& key ) const { QExplicitlySharedDataPointer result; KSecretsService::StringStringMap attrs; attrs[KSS_ATTR_ENTRYFOLDER] = folder; attrs["Label"] = key; KSecretsService::SearchCollectionItemsJob *searchJob = secretsCollection->searchItems(attrs); if (searchJob->exec()) { KSecretsService::SearchCollectionItemsJob::ItemList itemList = searchJob->items(); if ( !itemList.isEmpty() ) { result = itemList.first(); } else { kDebug(285) << "entry named " << key << " not found in folder " << folder; } } else { kDebug(285) << "Cannot exec KSecretsService::SearchCollectionItemsJob : " << searchJob->errorString(); } return result; } template int Wallet::WalletPrivate::readEntry(const QString& key, T& value) const { int rc = -1; QExplicitlySharedDataPointer item = findItem(key); if ( item ) { KSecretsService::GetSecretItemSecretJob *readJob = item->getSecret(); if ( readJob->exec() ) { KSecretsService::Secret theSecret = readJob->secret(); kDebug(285) << "Secret contentType is " << theSecret.contentType(); value = theSecret.value().value(); rc = 0; } else { kDebug(285) << "Cannot exec GetSecretItemSecretJob : " << readJob->errorString(); } } return rc; } bool Wallet::WalletPrivate::readSecret(const QString& key, KSecretsService::Secret& value) const { bool result = false; QExplicitlySharedDataPointer item = findItem(key); if ( item ) { KSecretsService::GetSecretItemSecretJob *readJob = item->getSecret(); if ( readJob->exec() ) { value = readJob->secret(); result = true; } else { kDebug(285) << "Cannot exec GetSecretItemSecretJob : " << readJob->errorString(); } } return result; } #endif int Wallet::readEntry(const QString& key, QByteArray& value) { int rc = -1; #ifdef HAVE_KSECRETSSERVICE if (walletLauncher->m_useKSecretsService) { return d->readEntry(key, value); } else { #endif if (d->handle == -1) { return rc; } QDBusReply r = walletLauncher->getInterface().readEntry(d->handle, d->folder, key, appid()); if (r.isValid()) { value = r; rc = 0; } #ifdef HAVE_KSECRETSSERVICE } #endif return rc; } #ifdef HAVE_KSECRETSSERVICE struct Wallet::WalletPrivate::InsertIntoEntryList { InsertIntoEntryList( QMap< QString, QByteArray> &value ) : _value( value ) {} bool operator() ( Wallet::WalletPrivate*, const QString& label, KSecretsService::SecretItem* item ) { bool result = false; KSecretsService::GetSecretItemSecretJob *readSecretJob = item->getSecret(); if ( readSecretJob->exec() ) { _value.insert( label, readSecretJob->secret().value().toByteArray() ); result = true; } else { kDebug(285) << "Cannot execute GetSecretItemSecretJob " << readSecretJob->errorString(); } return result; } QMap< QString, QByteArray > _value; }; #endif int Wallet::readEntryList(const QString& key, QMap& value) { int rc = -1; #ifdef HAVE_KSECRETSSERVICE if (walletLauncher->m_useKSecretsService) { rc = d->forEachItemThatMatches( key, WalletPrivate::InsertIntoEntryList( value ) ); } else { #endif registerTypes(); if (d->handle == -1) { return rc; } QDBusReply r = walletLauncher->getInterface().readEntryList(d->handle, d->folder, key, appid()); if (r.isValid()) { rc = 0; // convert to const QVariantMap val = r.value(); for( QVariantMap::const_iterator it = val.begin(); it != val.end(); ++it ) { value.insert(it.key(), it.value().toByteArray()); } } #ifdef HAVE_KSECRETSSERVICE } #endif return rc; } int Wallet::renameEntry(const QString& oldName, const QString& newName) { int rc = -1; #ifdef HAVE_KSECRETSSERVICE if (walletLauncher->m_useKSecretsService) { QExplicitlySharedDataPointer item = d->findItem(oldName); if (item) { KSecretsService::WriteItemPropertyJob *writeJob = item->setLabel(newName); if (!writeJob->exec()) { kDebug(285) << "Cannot exec WriteItemPropertyJob : " << writeJob->errorString(); } rc = writeJob->error(); } else { kDebug(285) << "Cannot locate item " << oldName << " in folder " << d->folder; } } else { #endif if (d->handle == -1) { return rc; } QDBusReply r = walletLauncher->getInterface().renameEntry(d->handle, d->folder, oldName, newName, appid()); if (r.isValid()) { rc = r; } #ifdef HAVE_KSECRETSSERVICE } #endif return rc; } int Wallet::readMap(const QString& key, QMap& value) { int rc = -1; #ifdef HAVE_KSECRETSSERVICE if (walletLauncher->m_useKSecretsService) { QByteArray ba; rc = d->readEntry< QByteArray >(key, ba); if ( rc == 0 && !ba.isEmpty()){ QDataStream ds( &ba, QIODevice::ReadOnly ); ds >> value; } } else { #endif registerTypes(); if (d->handle == -1) { return rc; } QDBusReply r = walletLauncher->getInterface().readMap(d->handle, d->folder, key, appid()); if (r.isValid()) { rc = 0; QByteArray v = r; if (!v.isEmpty()) { QDataStream ds(&v, QIODevice::ReadOnly); ds >> value; } } #ifdef HAVE_KSECRETSSERVICE } #endif return rc; } #ifdef HAVE_KSECRETSSERVICE struct Wallet::WalletPrivate::InsertIntoMapList { InsertIntoMapList( QMap< QString, QMap< QString, QString > > &value ) : _value( value ) {} bool operator() ( Wallet::WalletPrivate* d, const QString& label, KSecretsService::SecretItem* ) { bool result = false; QMap map; if ( d->readEntry< QMap< QString, QString> >(label, map) ) { _value.insert( label, map ); result = true; } return result; } QMap< QString, QMap< QString, QString> > &_value; }; #endif int Wallet::readMapList(const QString& key, QMap >& value) { int rc = -1; #ifdef HAVE_KSECRETSSERVICE if (walletLauncher->m_useKSecretsService) { rc = d->forEachItemThatMatches( key, WalletPrivate::InsertIntoMapList( value ) ); } else { #endif registerTypes(); if (d->handle == -1) { return rc; } QDBusReply r = walletLauncher->getInterface().readMapList(d->handle, d->folder, key, appid()); if (r.isValid()) { rc = 0; const QVariantMap val = r.value(); for( QVariantMap::const_iterator it = val.begin(); it != val.end(); ++it ) { QByteArray mapData = it.value().toByteArray(); if (!mapData.isEmpty()) { QDataStream ds(&mapData, QIODevice::ReadOnly); QMap v; ds >> v; value.insert(it.key(), v); } } } #ifdef HAVE_KSECRETSSERVICE } #endif return rc; } int Wallet::readPassword(const QString& key, QString& value) { int rc = -1; #ifdef HAVE_KSECRETSSERVICE if (walletLauncher->m_useKSecretsService) { rc = d->readEntry(key, value); } else { #endif if (d->handle == -1) { return rc; } QDBusReply r = walletLauncher->getInterface().readPassword(d->handle, d->folder, key, appid()); if (r.isValid()) { value = r; rc = 0; } #ifdef HAVE_KSECRETSSERVICE } #endif return rc; } #ifdef HAVE_KSECRETSSERVICE struct Wallet::WalletPrivate::InsertIntoPasswordList { InsertIntoPasswordList( QMap< QString, QString> &value ) : _value( value ) {} bool operator() ( Wallet::WalletPrivate* d, const QString& label, KSecretsService::SecretItem* ) { bool result = false; QString pwd; if ( d->readEntry( label, pwd ) == 0 ) { _value.insert( label, pwd ); result = true; } return result; } QMap< QString, QString > &_value; }; #endif int Wallet::readPasswordList(const QString& key, QMap& value) { int rc = -1; #ifdef HAVE_KSECRETSSERVICE if (walletLauncher->m_useKSecretsService) { rc = d->forEachItemThatMatches( key, WalletPrivate::InsertIntoPasswordList( value ) ); } else { #endif registerTypes(); if (d->handle == -1) { return rc; } QDBusReply r = walletLauncher->getInterface().readPasswordList(d->handle, d->folder, key, appid()); if (r.isValid()) { rc = 0; const QVariantMap val = r.value(); for( QVariantMap::const_iterator it = val.begin(); it != val.end(); ++it ) { value.insert(it.key(), it.value().toString()); } } #ifdef HAVE_KSECRETSSERVICE } #endif return rc; } int Wallet::writeEntry(const QString& key, const QByteArray& value, EntryType entryType) { int rc = -1; #ifdef HAVE_KSECRETSSERVICE if (walletLauncher->m_useKSecretsService) { rc = d->writeEntry( key, value, entryType ); } else { #endif if (d->handle == -1) { return rc; } QDBusReply r = walletLauncher->getInterface().writeEntry(d->handle, d->folder, key, value, int(entryType), appid()); if (r.isValid()) { rc = r; } #ifdef HAVE_KSECRETSSERVICE } #endif return rc; } int Wallet::writeEntry(const QString& key, const QByteArray& value) { int rc = -1; #ifdef HAVE_KSECRETSSERVICE if (walletLauncher->m_useKSecretsService) { rc = writeEntry( key, value, Stream ); } else { #endif if (d->handle == -1) { return rc; } QDBusReply r = walletLauncher->getInterface().writeEntry(d->handle, d->folder, key, value, appid()); if (r.isValid()) { rc = r; } #ifdef HAVE_KSECRETSSERVICE } #endif return rc; } int Wallet::writeMap(const QString& key, const QMap& value) { int rc = -1; #ifdef HAVE_KSECRETSSERVICE if (walletLauncher->m_useKSecretsService) { d->writeEntry( key, value, Map ); } else { #endif registerTypes(); if (d->handle == -1) { return rc; } QByteArray mapData; QDataStream ds(&mapData, QIODevice::WriteOnly); ds << value; QDBusReply r = walletLauncher->getInterface().writeMap(d->handle, d->folder, key, mapData, appid()); if (r.isValid()) { rc = r; } #ifdef HAVE_KSECRETSSERVICE } #endif return rc; } int Wallet::writePassword(const QString& key, const QString& value) { int rc = -1; #ifdef HAVE_KSECRETSSERVICE if (walletLauncher->m_useKSecretsService) { rc = d->writeEntry( key, value, Password ); } else { #endif if (d->handle == -1) { return rc; } QDBusReply r = walletLauncher->getInterface().writePassword(d->handle, d->folder, key, value, appid()); if (r.isValid()) { rc = r; } #ifdef HAVE_KSECRETSSERVICE } #endif return rc; } bool Wallet::hasEntry(const QString& key) { #ifdef HAVE_KSECRETSSERVICE if (walletLauncher->m_useKSecretsService) { QExplicitlySharedDataPointer item = d->findItem( key ); return item; } else { #endif if (d->handle == -1) { return false; } QDBusReply r = walletLauncher->getInterface().hasEntry(d->handle, d->folder, key, appid()); if (!r.isValid()) { kDebug(285) << "Invalid DBus reply: " << r.error(); return false; } else return r; #ifdef HAVE_KSECRETSSERVICE } #endif } int Wallet::removeEntry(const QString& key) { int rc = -1; #ifdef HAVE_KSECRETSSERVICE if (walletLauncher->m_useKSecretsService) { QExplicitlySharedDataPointer item = d->findItem( key ); if ( item ) { KSecretsService::SecretItemDeleteJob *deleteJob = item->deleteItem(); if ( !deleteJob->exec() ) { kDebug(285) << "Cannot execute SecretItemDeleteJob " << deleteJob->errorString(); } rc = deleteJob->error(); } } else { #endif if (d->handle == -1) { return rc; } QDBusReply r = walletLauncher->getInterface().removeEntry(d->handle, d->folder, key, appid()); if (r.isValid()) { rc = r; } #ifdef HAVE_KSECRETSSERVICE } #endif return rc; } Wallet::EntryType Wallet::entryType(const QString& key) { int rc = 0; #ifdef HAVE_KSECRETSSERVICE if (walletLauncher->m_useKSecretsService) { QExplicitlySharedDataPointer item = d->findItem( key ); if ( item ) { KSecretsService::ReadItemPropertyJob *readAttrsJob = item->attributes(); if ( readAttrsJob->exec() ) { KSecretsService::StringStringMap attrs = readAttrsJob->propertyValue().value(); if ( attrs.contains( KSS_ATTR_WALLETTYPE ) ) { QString entryType = attrs[KSS_ATTR_WALLETTYPE]; bool ok = false; rc = entryType.toInt( &ok ); if ( !ok ) { rc = 0; kDebug(285) << KSS_ATTR_WALLETTYPE << " attribute holds non int value " << attrs[KSS_ATTR_WALLETTYPE]; } } } else { kDebug(285) << "Cannot execute GetSecretItemSecretJob " << readAttrsJob->errorString(); } } } else { #endif if (d->handle == -1) { return Wallet::Unknown; } QDBusReply r = walletLauncher->getInterface().entryType(d->handle, d->folder, key, appid()); if (r.isValid()) { rc = r; } #ifdef HAVE_KSECRETSSERVICE } #endif return static_cast(rc); } void Wallet::WalletPrivate::walletServiceUnregistered() { if (handle >= 0) { q->slotWalletClosed(handle); } } void Wallet::slotFolderUpdated(const QString& wallet, const QString& folder) { #ifdef HAVE_KSECRETSSERVICE if (walletLauncher->m_useKSecretsService) { // TODO: implement this Q_ASSERT(0); } else { #endif if (d->name == wallet) { emit folderUpdated(folder); } #ifdef HAVE_KSECRETSSERVICE } #endif } void Wallet::slotFolderListUpdated(const QString& wallet) { #ifdef HAVE_KSECRETSSERVICE if (walletLauncher->m_useKSecretsService) { // TODO: implement this Q_ASSERT(0); } else { #endif if (d->name == wallet) { emit folderListUpdated(); } #ifdef HAVE_KSECRETSSERVICE } #endif } void Wallet::slotApplicationDisconnected(const QString& wallet, const QString& application) { #ifdef HAVE_KSECRETSSERVICE if (walletLauncher->m_useKSecretsService) { // TODO: implement this Q_ASSERT(0); } else { #endif if (d->handle >= 0 && d->name == wallet && application == appid()) { slotWalletClosed(d->handle); } #ifdef HAVE_KSECRETSSERVICE } #endif } void Wallet::walletAsyncOpened(int tId, int handle) { #ifdef HAVE_KSECRETSSERVICE if (walletLauncher->m_useKSecretsService) { // TODO: implement this Q_ASSERT(0); } else { #endif // ignore responses to calls other than ours if (d->transactionId != tId || d->handle != -1) { return; } // disconnect the async signal disconnect(this, SLOT(walletAsyncOpened(int,int))); d->handle = handle; emit walletOpened(handle > 0); #ifdef HAVE_KSECRETSSERVICE } #endif } void Wallet::emitWalletAsyncOpenError() { emit walletOpened(false); } void Wallet::emitWalletOpened() { emit walletOpened(true); } bool Wallet::folderDoesNotExist(const QString& wallet, const QString& folder) { #ifdef HAVE_KSECRETSSERVICE if (walletLauncher->m_useKSecretsService) { kDebug(285) << "WARNING: changing semantics of folderDoesNotExist with KSS: will prompt for the password"; Wallet *w = openWallet( wallet, 0, Synchronous ); if ( w ) { return !w->hasFolder( folder ); } else { return true; } } else { #endif QDBusReply r = walletLauncher->getInterface().folderDoesNotExist(wallet, folder); if (!r.isValid()) { kDebug(285) << "Invalid DBus reply: " << r.error(); return false; } else return r; #ifdef HAVE_KSECRETSSERVICE } #endif } bool Wallet::keyDoesNotExist(const QString& wallet, const QString& folder, const QString& key) { #ifdef HAVE_KSECRETSSERVICE if (walletLauncher->m_useKSecretsService) { kDebug(285) << "WARNING: changing semantics of keyDoesNotExist with KSS: will prompt for the password"; Wallet *w = openWallet( wallet, 0, Synchronous ); if ( w ) { return !w->hasEntry(key); } return false; } else { #endif QDBusReply r = walletLauncher->getInterface().keyDoesNotExist(wallet, folder, key); if (!r.isValid()) { kDebug(285) << "Invalid DBus reply: " << r.error(); return false; } else return r; #ifdef HAVE_KSECRETSSERVICE } #endif } KWalletDLauncher::KWalletDLauncher() : m_wallet(0), m_cgroup(KSharedConfig::openConfig("kwalletrc", KConfig::NoGlobals)->group("Wallet")) { m_useKSecretsService = m_cgroup.readEntry("UseKSecretsService", false); #ifdef HAVE_KSECRETSSERVICE if (m_useKSecretsService) { // NOOP } else { #endif m_wallet = new org::kde::KWallet(QString::fromLatin1(s_kwalletdServiceName), "/modules/kwalletd", QDBusConnection::sessionBus()); #ifdef HAVE_KSECRETSSERVICE } #endif } KWalletDLauncher::~KWalletDLauncher() { delete m_wallet; } org::kde::KWallet &KWalletDLauncher::getInterface() { // Q_ASSERT(!m_useKSecretsService); Q_ASSERT(m_wallet != 0); // check if kwalletd is already running if (!QDBusConnection::sessionBus().interface()->isServiceRegistered(QString::fromLatin1(s_kwalletdServiceName))) { // not running! check if it is enabled. bool walletEnabled = m_cgroup.readEntry("Enabled", true); if (walletEnabled) { // wallet is enabled! try launching it QString error; int ret = KToolInvocation::startServiceByDesktopPath("kwalletd.desktop", QStringList(), &error); if (ret > 0) { kError(285) << "Couldn't start kwalletd: " << error << endl; } if (!QDBusConnection::sessionBus().interface()->isServiceRegistered(QString::fromLatin1(s_kwalletdServiceName))) { kDebug(285) << "The kwalletd service is still not registered"; } else { kDebug(285) << "The kwalletd service has been registered"; } } else { kError(285) << "The kwalletd service has been disabled"; } } return *m_wallet; } } // namespace KWallet #include "moc_kwallet.cpp"