2011-11-14 09:56:55 +00:00
|
|
|
/******************************************************************************
|
2014-03-12 14:02:07 +00:00
|
|
|
* Copyright (C) 2011-2014 Frank Osterfeld <frank.osterfeld@gmail.com> *
|
2011-11-14 09:56:55 +00:00
|
|
|
* *
|
|
|
|
* This program 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. For licensing and distribution *
|
|
|
|
* details, check the accompanying file 'COPYING'. *
|
|
|
|
*****************************************************************************/
|
|
|
|
#include "keychain_p.h"
|
2014-01-04 12:15:08 +00:00
|
|
|
#include "gnomekeyring_p.h"
|
2011-11-14 09:56:55 +00:00
|
|
|
|
|
|
|
#include <QSettings>
|
|
|
|
|
2013-10-13 13:50:00 +00:00
|
|
|
#include <QScopedPointer>
|
2012-06-09 20:11:16 +00:00
|
|
|
|
2011-11-14 09:56:55 +00:00
|
|
|
using namespace QKeychain;
|
|
|
|
|
2013-10-12 18:24:49 +00:00
|
|
|
static QString typeKey( const QString& key )
|
|
|
|
{
|
|
|
|
return QString::fromLatin1( "%1/type" ).arg( key );
|
|
|
|
}
|
|
|
|
|
|
|
|
static QString dataKey( const QString& key )
|
|
|
|
{
|
|
|
|
return QString::fromLatin1( "%1/data" ).arg( key );
|
|
|
|
}
|
|
|
|
|
2013-03-19 11:24:15 +00:00
|
|
|
enum KeyringBackend {
|
|
|
|
Backend_GnomeKeyring,
|
2015-02-21 20:01:25 +00:00
|
|
|
Backend_Kwallet4,
|
|
|
|
Backend_Kwallet5
|
2013-03-19 11:24:15 +00:00
|
|
|
};
|
2013-07-22 17:41:45 +00:00
|
|
|
|
2014-04-04 13:00:07 +00:00
|
|
|
enum DesktopEnvironment {
|
|
|
|
DesktopEnv_Gnome,
|
|
|
|
DesktopEnv_Kde4,
|
2015-02-21 20:01:25 +00:00
|
|
|
DesktopEnv_Plasma5,
|
2014-04-04 13:00:07 +00:00
|
|
|
DesktopEnv_Unity,
|
|
|
|
DesktopEnv_Xfce,
|
|
|
|
DesktopEnv_Other
|
|
|
|
};
|
|
|
|
|
|
|
|
// the following detection algorithm is derived from chromium,
|
|
|
|
// licensed under BSD, see base/nix/xdg_util.cc
|
|
|
|
|
2015-02-21 20:11:34 +00:00
|
|
|
static DesktopEnvironment getKdeVersion() {
|
|
|
|
QString value = qgetenv("KDE_SESSION_VERSION");
|
|
|
|
if ( value == "5" ) {
|
|
|
|
return DesktopEnv_Plasma5;
|
|
|
|
} else if (value == "4" ) {
|
|
|
|
return DesktopEnv_Kde4;
|
|
|
|
} else {
|
|
|
|
// most likely KDE3
|
|
|
|
return DesktopEnv_Other;
|
|
|
|
}
|
|
|
|
}
|
2014-04-04 13:00:07 +00:00
|
|
|
|
|
|
|
static DesktopEnvironment detectDesktopEnvironment() {
|
|
|
|
QByteArray xdgCurrentDesktop = qgetenv("XDG_CURRENT_DESKTOP");
|
|
|
|
if ( xdgCurrentDesktop == "GNOME" ) {
|
|
|
|
return DesktopEnv_Gnome;
|
|
|
|
} else if ( xdgCurrentDesktop == "Unity" ) {
|
2015-02-21 20:11:34 +00:00
|
|
|
return DesktopEnv_Unity;
|
2014-04-04 13:00:07 +00:00
|
|
|
} else if ( xdgCurrentDesktop == "KDE" ) {
|
2015-02-21 20:11:34 +00:00
|
|
|
return getKdeVersion();
|
2014-04-04 13:00:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QByteArray desktopSession = qgetenv("DESKTOP_SESSION");
|
|
|
|
if ( desktopSession == "gnome" ) {
|
|
|
|
return DesktopEnv_Gnome;
|
|
|
|
} else if ( desktopSession == "kde" ) {
|
2015-02-21 20:11:34 +00:00
|
|
|
return getKdeVersion();
|
2014-04-04 13:00:07 +00:00
|
|
|
} else if ( desktopSession == "kde4" ) {
|
|
|
|
return DesktopEnv_Kde4;
|
|
|
|
} else if ( desktopSession.contains("xfce") || desktopSession == "xubuntu" ) {
|
|
|
|
return DesktopEnv_Xfce;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !qgetenv("GNOME_DESKTOP_SESSION_ID").isEmpty() ) {
|
|
|
|
return DesktopEnv_Gnome;
|
|
|
|
} else if ( !qgetenv("KDE_FULL_SESSION").isEmpty() ) {
|
2015-02-21 20:11:34 +00:00
|
|
|
return getKdeVersion();
|
2014-04-04 13:00:07 +00:00
|
|
|
}
|
2014-04-07 19:35:17 +00:00
|
|
|
|
|
|
|
return DesktopEnv_Other;
|
2014-04-04 13:00:07 +00:00
|
|
|
}
|
|
|
|
|
2013-03-19 11:24:15 +00:00
|
|
|
static KeyringBackend detectKeyringBackend()
|
|
|
|
{
|
2014-04-04 13:00:07 +00:00
|
|
|
switch (detectDesktopEnvironment()) {
|
|
|
|
case DesktopEnv_Kde4:
|
2015-02-21 20:01:25 +00:00
|
|
|
return Backend_Kwallet4;
|
|
|
|
break;
|
|
|
|
case DesktopEnv_Plasma5:
|
|
|
|
return Backend_Kwallet5;
|
2014-04-04 13:00:07 +00:00
|
|
|
break;
|
|
|
|
// fall through
|
|
|
|
case DesktopEnv_Gnome:
|
|
|
|
case DesktopEnv_Unity:
|
|
|
|
case DesktopEnv_Xfce:
|
|
|
|
case DesktopEnv_Other:
|
|
|
|
default:
|
|
|
|
if ( GnomeKeyring::isAvailable() ) {
|
|
|
|
return Backend_GnomeKeyring;
|
|
|
|
} else {
|
2015-02-21 20:01:25 +00:00
|
|
|
return Backend_Kwallet4;
|
2014-04-04 13:00:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-19 11:24:15 +00:00
|
|
|
}
|
2013-07-22 17:41:45 +00:00
|
|
|
|
2013-03-19 11:24:15 +00:00
|
|
|
static KeyringBackend getKeyringBackend()
|
|
|
|
{
|
|
|
|
static KeyringBackend backend = detectKeyringBackend();
|
|
|
|
return backend;
|
|
|
|
}
|
|
|
|
|
2012-07-27 21:10:47 +00:00
|
|
|
void ReadPasswordJobPrivate::scheduledStart() {
|
2013-03-19 11:24:15 +00:00
|
|
|
switch ( getKeyringBackend() ) {
|
|
|
|
case Backend_GnomeKeyring:
|
|
|
|
if ( !GnomeKeyring::find_network_password( key.toUtf8().constData(), q->service().toUtf8().constData(),
|
|
|
|
reinterpret_cast<GnomeKeyring::OperationGetStringCallback>( &ReadPasswordJobPrivate::gnomeKeyring_cb ),
|
2013-07-22 17:41:45 +00:00
|
|
|
this, 0 ) )
|
2013-03-19 11:24:15 +00:00
|
|
|
q->emitFinishedWithError( OtherError, tr("Unknown error") );
|
|
|
|
break;
|
|
|
|
|
2015-02-21 20:01:25 +00:00
|
|
|
case Backend_Kwallet4:
|
2013-07-22 15:52:07 +00:00
|
|
|
if ( QDBusConnection::sessionBus().isConnected() )
|
|
|
|
{
|
|
|
|
iface = new org::kde::KWallet( QLatin1String("org.kde.kwalletd"), QLatin1String("/modules/kwalletd"), QDBusConnection::sessionBus(), this );
|
2013-08-22 08:58:46 +00:00
|
|
|
const QDBusPendingReply<QString> reply = iface->networkWallet();
|
2013-07-22 15:52:07 +00:00
|
|
|
QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher( reply, this );
|
2013-08-22 08:58:46 +00:00
|
|
|
connect( watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(kwalletWalletFound(QDBusPendingCallWatcher*)) );
|
2013-07-22 15:52:07 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-06-06 12:25:07 +00:00
|
|
|
// D-Bus is not reachable so none can tell us something about KWalletd
|
2013-10-12 18:24:49 +00:00
|
|
|
QDBusError err( QDBusError::NoServer, tr("D-Bus is not running") );
|
2013-07-22 15:52:07 +00:00
|
|
|
fallbackOnError( err );
|
|
|
|
}
|
2013-03-19 11:24:15 +00:00
|
|
|
break;
|
2015-02-21 20:01:25 +00:00
|
|
|
case Backend_Kwallet5:
|
|
|
|
break;
|
2013-03-19 11:24:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-22 08:58:46 +00:00
|
|
|
void ReadPasswordJobPrivate::kwalletWalletFound(QDBusPendingCallWatcher *watcher)
|
|
|
|
{
|
|
|
|
watcher->deleteLater();
|
|
|
|
const QDBusPendingReply<QString> reply = *watcher;
|
|
|
|
const QDBusPendingReply<int> pendingReply = iface->open( reply.value(), 0, q->service() );
|
|
|
|
QDBusPendingCallWatcher* pendingWatcher = new QDBusPendingCallWatcher( pendingReply, this );
|
|
|
|
connect( pendingWatcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(kwalletOpenFinished(QDBusPendingCallWatcher*)) );
|
|
|
|
}
|
|
|
|
|
2013-07-22 18:16:26 +00:00
|
|
|
static QPair<Error, QString> mapGnomeKeyringError( int result )
|
2013-03-19 11:24:15 +00:00
|
|
|
{
|
2013-07-22 18:16:26 +00:00
|
|
|
Q_ASSERT( result != GnomeKeyring::RESULT_OK );
|
2013-03-19 11:24:15 +00:00
|
|
|
|
2013-07-22 18:16:26 +00:00
|
|
|
switch ( result ) {
|
2013-07-22 15:52:07 +00:00
|
|
|
case GnomeKeyring::RESULT_DENIED:
|
2013-07-22 18:16:26 +00:00
|
|
|
return qMakePair( AccessDenied, QObject::tr("Access to keychain denied") );
|
2013-07-22 15:52:07 +00:00
|
|
|
case GnomeKeyring::RESULT_NO_KEYRING_DAEMON:
|
2013-07-22 18:16:26 +00:00
|
|
|
return qMakePair( NoBackendAvailable, QObject::tr("No keyring daemon") );
|
2013-07-22 15:52:07 +00:00
|
|
|
case GnomeKeyring::RESULT_ALREADY_UNLOCKED:
|
2013-07-22 18:16:26 +00:00
|
|
|
return qMakePair( OtherError, QObject::tr("Already unlocked") );
|
2013-07-22 15:52:07 +00:00
|
|
|
case GnomeKeyring::RESULT_NO_SUCH_KEYRING:
|
2013-07-22 18:16:26 +00:00
|
|
|
return qMakePair( OtherError, QObject::tr("No such keyring") );
|
2013-07-22 15:52:07 +00:00
|
|
|
case GnomeKeyring::RESULT_BAD_ARGUMENTS:
|
2013-07-22 18:16:26 +00:00
|
|
|
return qMakePair( OtherError, QObject::tr("Bad arguments") );
|
2013-07-22 15:52:07 +00:00
|
|
|
case GnomeKeyring::RESULT_IO_ERROR:
|
2013-07-22 18:16:26 +00:00
|
|
|
return qMakePair( OtherError, QObject::tr("I/O error") );
|
2013-07-22 15:52:07 +00:00
|
|
|
case GnomeKeyring::RESULT_CANCELLED:
|
2013-07-22 18:16:26 +00:00
|
|
|
return qMakePair( OtherError, QObject::tr("Cancelled") );
|
2013-07-22 15:52:07 +00:00
|
|
|
case GnomeKeyring::RESULT_KEYRING_ALREADY_EXISTS:
|
2013-07-22 18:16:26 +00:00
|
|
|
return qMakePair( OtherError, QObject::tr("Keyring already exists") );
|
2013-07-22 15:52:07 +00:00
|
|
|
case GnomeKeyring::RESULT_NO_MATCH:
|
2013-07-22 18:16:26 +00:00
|
|
|
return qMakePair( EntryNotFound, QObject::tr("No match") );
|
2013-07-22 15:52:07 +00:00
|
|
|
default:
|
|
|
|
break;
|
2013-06-06 12:25:07 +00:00
|
|
|
}
|
2013-07-22 18:16:26 +00:00
|
|
|
|
|
|
|
return qMakePair( OtherError, QObject::tr("Unknown error") );
|
|
|
|
}
|
|
|
|
|
|
|
|
void ReadPasswordJobPrivate::gnomeKeyring_cb( int result, const char* string, ReadPasswordJobPrivate* self )
|
|
|
|
{
|
|
|
|
if ( result == GnomeKeyring::RESULT_OK ) {
|
|
|
|
if ( self->dataType == ReadPasswordJobPrivate::Text )
|
|
|
|
self->data = string;
|
|
|
|
else
|
|
|
|
self->data = QByteArray::fromBase64( string );
|
|
|
|
self->q->emitFinished();
|
|
|
|
} else {
|
|
|
|
const QPair<Error, QString> errorResult = mapGnomeKeyringError( result );
|
|
|
|
self->q->emitFinishedWithError( errorResult.first, errorResult.second );
|
|
|
|
}
|
2012-05-08 08:47:38 +00:00
|
|
|
}
|
|
|
|
|
2013-06-06 12:25:07 +00:00
|
|
|
void ReadPasswordJobPrivate::fallbackOnError(const QDBusError& err )
|
|
|
|
{
|
2013-10-13 13:50:00 +00:00
|
|
|
QScopedPointer<QSettings> local( !q->settings() ? new QSettings( q->service() ) : 0 );
|
|
|
|
QSettings* actual = q->settings() ? q->settings() : local.data();
|
2012-06-09 20:11:16 +00:00
|
|
|
|
2013-10-12 18:24:49 +00:00
|
|
|
if ( q->insecureFallback() && actual->contains( dataKey( key ) ) ) {
|
2012-06-09 20:11:16 +00:00
|
|
|
|
2013-11-11 19:01:22 +00:00
|
|
|
const WritePasswordJobPrivate::Mode mode = WritePasswordJobPrivate::stringToMode( actual->value( typeKey( key ) ).toString() );
|
|
|
|
if (mode == WritePasswordJobPrivate::Binary)
|
|
|
|
dataType = Binary;
|
|
|
|
else
|
|
|
|
dataType = Text;
|
2013-10-12 18:24:49 +00:00
|
|
|
data = actual->value( dataKey( key ) ).toByteArray();
|
2013-06-06 12:25:07 +00:00
|
|
|
|
|
|
|
q->emitFinished();
|
|
|
|
} else {
|
|
|
|
if ( err.type() == QDBusError::ServiceUnknown ) //KWalletd not running
|
|
|
|
q->emitFinishedWithError( NoBackendAvailable, tr("No keychain service available") );
|
|
|
|
else
|
|
|
|
q->emitFinishedWithError( OtherError, tr("Could not open wallet: %1; %2").arg( QDBusError::errorString( err.type() ), err.message() ) );
|
|
|
|
}
|
|
|
|
}
|
2012-06-09 20:11:16 +00:00
|
|
|
|
2013-06-06 12:25:07 +00:00
|
|
|
void ReadPasswordJobPrivate::kwalletOpenFinished( QDBusPendingCallWatcher* watcher ) {
|
|
|
|
watcher->deleteLater();
|
|
|
|
const QDBusPendingReply<int> reply = *watcher;
|
2012-06-09 20:11:16 +00:00
|
|
|
|
2013-10-13 13:50:00 +00:00
|
|
|
QScopedPointer<QSettings> local( !q->settings() ? new QSettings( q->service() ) : 0 );
|
|
|
|
QSettings* actual = q->settings() ? q->settings() : local.data();
|
2013-06-06 12:25:07 +00:00
|
|
|
|
|
|
|
if ( reply.isError() ) {
|
|
|
|
fallbackOnError( reply.error() );
|
|
|
|
return;
|
2012-06-09 20:11:16 +00:00
|
|
|
}
|
|
|
|
|
2013-10-12 18:24:49 +00:00
|
|
|
if ( actual->contains( dataKey( key ) ) ) {
|
2012-06-09 20:11:16 +00:00
|
|
|
// We previously stored data in the insecure QSettings, but now have KWallet available.
|
|
|
|
// Do the migration
|
|
|
|
|
2013-10-12 18:24:49 +00:00
|
|
|
data = actual->value( dataKey( key ) ).toByteArray();
|
2013-11-11 19:01:22 +00:00
|
|
|
const WritePasswordJobPrivate::Mode mode = WritePasswordJobPrivate::stringToMode( actual->value( typeKey( key ) ).toString() );
|
2012-06-09 20:11:16 +00:00
|
|
|
actual->remove( key );
|
|
|
|
|
|
|
|
q->emitFinished();
|
|
|
|
|
|
|
|
|
|
|
|
WritePasswordJob* j = new WritePasswordJob( q->service(), 0 );
|
|
|
|
j->setSettings( q->settings() );
|
|
|
|
j->setKey( key );
|
|
|
|
j->setAutoDelete( true );
|
|
|
|
if ( mode == WritePasswordJobPrivate::Binary )
|
|
|
|
j->setBinaryData( data );
|
|
|
|
else if ( mode == WritePasswordJobPrivate::Text )
|
|
|
|
j->setTextData( QString::fromUtf8( data ) );
|
2012-05-08 15:23:26 +00:00
|
|
|
else
|
2012-06-09 20:11:16 +00:00
|
|
|
Q_ASSERT( false );
|
|
|
|
|
|
|
|
j->start();
|
|
|
|
|
2012-05-08 08:47:38 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
walletHandle = reply.value();
|
|
|
|
|
2012-05-08 15:38:14 +00:00
|
|
|
if ( walletHandle < 0 ) {
|
|
|
|
q->emitFinishedWithError( AccessDenied, tr("Access to keychain denied") );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-05-08 08:47:38 +00:00
|
|
|
const QDBusPendingReply<int> nextReply = iface->entryType( walletHandle, q->service(), key, q->service() );
|
|
|
|
QDBusPendingCallWatcher* nextWatcher = new QDBusPendingCallWatcher( nextReply, this );
|
|
|
|
connect( nextWatcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(kwalletEntryTypeFinished(QDBusPendingCallWatcher*)) );
|
|
|
|
}
|
|
|
|
|
2013-10-12 17:57:48 +00:00
|
|
|
//Must be in sync with KWallet::EntryType (kwallet.h)
|
|
|
|
enum KWalletEntryType {
|
|
|
|
Unknown=0,
|
|
|
|
Password,
|
|
|
|
Stream,
|
|
|
|
Map
|
|
|
|
};
|
|
|
|
|
2012-07-27 21:10:47 +00:00
|
|
|
void ReadPasswordJobPrivate::kwalletEntryTypeFinished( QDBusPendingCallWatcher* watcher ) {
|
2012-05-08 08:47:38 +00:00
|
|
|
watcher->deleteLater();
|
|
|
|
if ( watcher->isError() ) {
|
|
|
|
const QDBusError err = watcher->error();
|
|
|
|
q->emitFinishedWithError( OtherError, tr("Could not determine data type: %1; %2").arg( QDBusError::errorString( err.type() ), err.message() ) );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const QDBusPendingReply<int> reply = *watcher;
|
2013-10-12 17:57:48 +00:00
|
|
|
const int value = reply.value();
|
2012-05-08 08:47:38 +00:00
|
|
|
|
2013-10-12 17:57:48 +00:00
|
|
|
switch ( value ) {
|
|
|
|
case Unknown:
|
|
|
|
q->emitFinishedWithError( EntryNotFound, tr("Entry not found") );
|
|
|
|
return;
|
|
|
|
case Password:
|
|
|
|
dataType = Text;
|
|
|
|
break;
|
|
|
|
case Stream:
|
|
|
|
dataType = Binary;
|
|
|
|
break;
|
|
|
|
case Map:
|
|
|
|
q->emitFinishedWithError( EntryNotFound, tr("Unsupported entry type 'Map'") );
|
|
|
|
return;
|
|
|
|
default:
|
|
|
|
q->emitFinishedWithError( OtherError, tr("Unknown kwallet entry type '%1'").arg( value ) );
|
|
|
|
return;
|
|
|
|
}
|
2012-05-08 08:47:38 +00:00
|
|
|
|
|
|
|
const QDBusPendingCall nextReply = dataType == Text
|
|
|
|
? QDBusPendingCall( iface->readPassword( walletHandle, q->service(), key, q->service() ) )
|
|
|
|
: QDBusPendingCall( iface->readEntry( walletHandle, q->service(), key, q->service() ) );
|
|
|
|
QDBusPendingCallWatcher* nextWatcher = new QDBusPendingCallWatcher( nextReply, this );
|
|
|
|
connect( nextWatcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(kwalletReadFinished(QDBusPendingCallWatcher*)) );
|
|
|
|
}
|
|
|
|
|
2012-07-27 21:10:47 +00:00
|
|
|
void ReadPasswordJobPrivate::kwalletReadFinished( QDBusPendingCallWatcher* watcher ) {
|
2012-05-08 08:47:38 +00:00
|
|
|
watcher->deleteLater();
|
|
|
|
if ( watcher->isError() ) {
|
|
|
|
const QDBusError err = watcher->error();
|
|
|
|
q->emitFinishedWithError( OtherError, tr("Could not read password: %1; %2").arg( QDBusError::errorString( err.type() ), err.message() ) );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( dataType == Binary ) {
|
|
|
|
QDBusPendingReply<QByteArray> reply = *watcher;
|
|
|
|
data = reply.value();
|
|
|
|
} else {
|
|
|
|
QDBusPendingReply<QString> reply = *watcher;
|
|
|
|
data = reply.value().toUtf8();
|
|
|
|
}
|
|
|
|
q->emitFinished();
|
2011-11-14 09:56:55 +00:00
|
|
|
}
|
|
|
|
|
2012-07-27 21:10:47 +00:00
|
|
|
void WritePasswordJobPrivate::scheduledStart() {
|
2013-03-19 11:24:15 +00:00
|
|
|
switch ( getKeyringBackend() ) {
|
|
|
|
case Backend_GnomeKeyring:
|
|
|
|
if ( mode == WritePasswordJobPrivate::Delete ) {
|
|
|
|
if ( !GnomeKeyring::delete_network_password( key.toUtf8().constData(), q->service().toUtf8().constData(),
|
|
|
|
reinterpret_cast<GnomeKeyring::OperationDoneCallback>( &WritePasswordJobPrivate::gnomeKeyring_cb ),
|
2013-07-22 17:41:45 +00:00
|
|
|
this, 0 ) )
|
2013-03-19 11:24:15 +00:00
|
|
|
q->emitFinishedWithError( OtherError, tr("Unknown error") );
|
|
|
|
} else {
|
|
|
|
QByteArray password = mode == WritePasswordJobPrivate::Text ? textData.toUtf8() : binaryData.toBase64();
|
|
|
|
QByteArray service = q->service().toUtf8();
|
|
|
|
if ( !GnomeKeyring::store_network_password( GnomeKeyring::GNOME_KEYRING_DEFAULT, service.constData(),
|
|
|
|
key.toUtf8().constData(), service.constData(), password.constData(),
|
|
|
|
reinterpret_cast<GnomeKeyring::OperationDoneCallback>( &WritePasswordJobPrivate::gnomeKeyring_cb ),
|
2013-07-22 17:41:45 +00:00
|
|
|
this, 0 ) )
|
2013-03-19 11:24:15 +00:00
|
|
|
q->emitFinishedWithError( OtherError, tr("Unknown error") );
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2015-02-21 20:01:25 +00:00
|
|
|
case Backend_Kwallet4:
|
2013-07-22 15:52:07 +00:00
|
|
|
if ( QDBusConnection::sessionBus().isConnected() )
|
|
|
|
{
|
|
|
|
iface = new org::kde::KWallet( QLatin1String("org.kde.kwalletd"), QLatin1String("/modules/kwalletd"), QDBusConnection::sessionBus(), this );
|
2014-08-17 15:17:25 +00:00
|
|
|
const QDBusPendingReply<QString> reply = iface->networkWallet();
|
2013-07-22 15:52:07 +00:00
|
|
|
QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher( reply, this );
|
2014-08-17 15:17:25 +00:00
|
|
|
connect( watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(kwalletWalletFound(QDBusPendingCallWatcher*)) );
|
2013-07-22 15:52:07 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// D-Bus is not reachable so none can tell us something about KWalletd
|
2013-10-12 18:24:49 +00:00
|
|
|
QDBusError err( QDBusError::NoServer, tr("D-Bus is not running") );
|
2013-07-22 15:52:07 +00:00
|
|
|
fallbackOnError( err );
|
|
|
|
}
|
2015-02-21 20:01:25 +00:00
|
|
|
break;
|
|
|
|
case Backend_Kwallet5:
|
|
|
|
break;
|
2013-06-06 12:25:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-11 19:01:22 +00:00
|
|
|
QString WritePasswordJobPrivate::modeToString(Mode m)
|
|
|
|
{
|
|
|
|
switch (m) {
|
|
|
|
case Delete:
|
|
|
|
return QLatin1String("Delete");
|
|
|
|
case Text:
|
|
|
|
return QLatin1String("Text");
|
|
|
|
case Binary:
|
|
|
|
return QLatin1String("Binary");
|
|
|
|
}
|
|
|
|
|
|
|
|
Q_ASSERT_X(false, Q_FUNC_INFO, "Unhandled Mode value");
|
|
|
|
return QString();
|
|
|
|
}
|
|
|
|
|
|
|
|
WritePasswordJobPrivate::Mode WritePasswordJobPrivate::stringToMode(const QString& s)
|
|
|
|
{
|
|
|
|
if (s == QLatin1String("Delete") || s == QLatin1String("0"))
|
|
|
|
return Delete;
|
|
|
|
if (s == QLatin1String("Text") || s == QLatin1String("1"))
|
|
|
|
return Text;
|
|
|
|
if (s == QLatin1String("Binary") || s == QLatin1String("2"))
|
|
|
|
return Binary;
|
|
|
|
|
2013-11-11 19:34:44 +00:00
|
|
|
qCritical("Unexpected mode string '%s'", qPrintable(s));
|
2013-11-11 19:01:22 +00:00
|
|
|
|
|
|
|
return Text;
|
|
|
|
}
|
|
|
|
|
2013-06-06 12:25:07 +00:00
|
|
|
void WritePasswordJobPrivate::fallbackOnError(const QDBusError &err)
|
|
|
|
{
|
2013-10-13 13:50:00 +00:00
|
|
|
QScopedPointer<QSettings> local( !q->settings() ? new QSettings( q->service() ) : 0 );
|
|
|
|
QSettings* actual = q->settings() ? q->settings() : local.data();
|
2013-06-06 12:25:07 +00:00
|
|
|
|
2013-07-22 18:01:37 +00:00
|
|
|
if ( !q->insecureFallback() ) {
|
|
|
|
q->emitFinishedWithError( OtherError, tr("Could not open wallet: %1; %2").arg( QDBusError::errorString( err.type() ), err.message() ) );
|
|
|
|
return;
|
|
|
|
}
|
2013-06-06 12:25:07 +00:00
|
|
|
|
2013-07-22 18:01:37 +00:00
|
|
|
if ( mode == Delete ) {
|
|
|
|
actual->remove( key );
|
2013-06-06 12:25:07 +00:00
|
|
|
actual->sync();
|
|
|
|
|
|
|
|
q->emitFinished();
|
2013-07-22 18:01:37 +00:00
|
|
|
return;
|
2013-07-22 18:16:26 +00:00
|
|
|
}
|
2013-07-22 18:01:37 +00:00
|
|
|
|
2013-11-11 19:01:22 +00:00
|
|
|
actual->setValue( QString::fromLatin1( "%1/type" ).arg( key ), mode );
|
2013-07-22 18:01:37 +00:00
|
|
|
if ( mode == Text )
|
2013-10-12 18:24:49 +00:00
|
|
|
actual->setValue( QString::fromLatin1( "%1/data" ).arg( key ), textData.toUtf8() );
|
2013-07-22 18:01:37 +00:00
|
|
|
else if ( mode == Binary )
|
2013-10-12 18:24:49 +00:00
|
|
|
actual->setValue( QString::fromLatin1( "%1/data" ).arg( key ), binaryData );
|
2013-07-22 18:01:37 +00:00
|
|
|
actual->sync();
|
|
|
|
|
|
|
|
q->emitFinished();
|
2013-07-22 15:52:07 +00:00
|
|
|
}
|
|
|
|
|
2013-03-19 11:24:15 +00:00
|
|
|
void WritePasswordJobPrivate::gnomeKeyring_cb( int result, WritePasswordJobPrivate* self )
|
|
|
|
{
|
2013-07-22 18:16:26 +00:00
|
|
|
if ( result == GnomeKeyring::RESULT_OK ) {
|
2013-07-22 15:52:07 +00:00
|
|
|
self->q->emitFinished();
|
2013-07-22 18:16:26 +00:00
|
|
|
} else {
|
|
|
|
const QPair<Error, QString> errorResult = mapGnomeKeyringError( result );
|
|
|
|
self->q->emitFinishedWithError( errorResult.first, errorResult.second );
|
2013-06-06 12:25:07 +00:00
|
|
|
}
|
2012-05-07 16:21:22 +00:00
|
|
|
}
|
|
|
|
|
2014-08-17 15:17:25 +00:00
|
|
|
void WritePasswordJobPrivate::kwalletWalletFound(QDBusPendingCallWatcher *watcher)
|
|
|
|
{
|
|
|
|
watcher->deleteLater();
|
|
|
|
const QDBusPendingReply<QString> reply = *watcher;
|
|
|
|
const QDBusPendingReply<int> pendingReply = iface->open( reply.value(), 0, q->service() );
|
|
|
|
QDBusPendingCallWatcher* pendingWatcher = new QDBusPendingCallWatcher( pendingReply, this );
|
|
|
|
connect( pendingWatcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(kwalletOpenFinished(QDBusPendingCallWatcher*)) );
|
|
|
|
}
|
|
|
|
|
2012-07-27 21:10:47 +00:00
|
|
|
void WritePasswordJobPrivate::kwalletOpenFinished( QDBusPendingCallWatcher* watcher ) {
|
2012-05-07 16:21:22 +00:00
|
|
|
watcher->deleteLater();
|
|
|
|
QDBusPendingReply<int> reply = *watcher;
|
2012-06-09 20:11:16 +00:00
|
|
|
|
2013-10-13 13:50:00 +00:00
|
|
|
QScopedPointer<QSettings> local( !q->settings() ? new QSettings( q->service() ) : 0 );
|
|
|
|
QSettings* actual = q->settings() ? q->settings() : local.data();
|
2012-06-09 20:11:16 +00:00
|
|
|
|
2012-05-07 16:21:22 +00:00
|
|
|
if ( reply.isError() ) {
|
2013-06-06 12:25:07 +00:00
|
|
|
fallbackOnError( reply.error() );
|
2012-05-07 16:21:22 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-06-09 20:11:16 +00:00
|
|
|
if ( actual->contains( key ) )
|
|
|
|
{
|
|
|
|
// If we had previously written to QSettings, but we now have a kwallet available, migrate and delete old insecure data
|
|
|
|
actual->remove( key );
|
|
|
|
actual->sync();
|
|
|
|
}
|
|
|
|
|
2012-05-07 16:21:22 +00:00
|
|
|
const int handle = reply.value();
|
|
|
|
|
2012-05-08 15:38:14 +00:00
|
|
|
if ( handle < 0 ) {
|
|
|
|
q->emitFinishedWithError( AccessDenied, tr("Access to keychain denied") );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-05-07 16:21:22 +00:00
|
|
|
QDBusPendingReply<int> nextReply;
|
|
|
|
|
|
|
|
if ( !textData.isEmpty() )
|
|
|
|
nextReply = iface->writePassword( handle, q->service(), key, textData, q->service() );
|
|
|
|
else if ( !binaryData.isEmpty() )
|
|
|
|
nextReply = iface->writeEntry( handle, q->service(), key, binaryData, q->service() );
|
|
|
|
else
|
|
|
|
nextReply = iface->removeEntry( handle, q->service(), key, q->service() );
|
|
|
|
|
|
|
|
QDBusPendingCallWatcher* nextWatcher = new QDBusPendingCallWatcher( nextReply, this );
|
|
|
|
connect( nextWatcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(kwalletWriteFinished(QDBusPendingCallWatcher*)) );
|
|
|
|
}
|
|
|
|
|
2012-07-27 21:10:47 +00:00
|
|
|
void WritePasswordJobPrivate::kwalletWriteFinished( QDBusPendingCallWatcher* watcher ) {
|
2012-05-07 16:21:22 +00:00
|
|
|
watcher->deleteLater();
|
|
|
|
QDBusPendingReply<int> reply = *watcher;
|
|
|
|
if ( reply.isError() ) {
|
|
|
|
const QDBusError err = reply.error();
|
|
|
|
q->emitFinishedWithError( OtherError, tr("Could not open wallet: %1; %2").arg( QDBusError::errorString( err.type() ), err.message() ) );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
q->emitFinished();
|
2011-11-14 09:56:55 +00:00
|
|
|
}
|