Merge pull request #56 from akallabeth/refactor_win_cred_store

Refactor win cred store
This commit is contained in:
Frank Osterfeld 2015-12-04 11:47:36 +01:00
commit 08be0593e1
7 changed files with 354 additions and 294 deletions

View File

@ -13,6 +13,13 @@ include(GNUInstallDirs)
option(BUILD_WITH_QT4 "Build qtkeychain with Qt4 no matter if Qt5 was found" OFF)
if (WIN32)
option(USE_CREDENTIAL_STORE "Build with windows CredentialStore support" ON)
if (USE_CREDENTIAL_STORE)
add_definitions(-DUSE_CREDENTIAL_STORE=1)
endif()
endif()
if( NOT BUILD_WITH_QT4 )
# try Qt5 first, and prefer that if found

View File

@ -11,9 +11,9 @@
using namespace QKeychain;
Job::Job( const QString& service, QObject *parent )
Job::Job( JobPrivate *q, QObject *parent )
: QObject( parent )
, d ( new JobPrivate( service ) ) {
, d ( q ) {
}
Job::~Job() {
@ -52,6 +52,10 @@ void Job::setInsecureFallback( bool insecureFallback ) {
d->insecureFallback = insecureFallback;
}
void Job::doStart() {
JobExecutor::instance()->enqueue( this );
}
void Job::emitFinished() {
emit finished( this );
if ( d->autoDelete )
@ -64,6 +68,10 @@ void Job::emitFinishedWithError( Error error, const QString& errorString ) {
emitFinished();
}
void Job::scheduledStart() {
d->scheduledStart();
}
Error Job::error() const {
return d->error;
}
@ -81,12 +89,11 @@ void Job::setErrorString( const QString& errorString ) {
}
ReadPasswordJob::ReadPasswordJob( const QString& service, QObject* parent )
: Job( service, parent )
, d( new ReadPasswordJobPrivate( this ) )
{}
: Job( new ReadPasswordJobPrivate( service, this ), parent ) {
}
ReadPasswordJob::~ReadPasswordJob() {
delete d;
}
QString ReadPasswordJob::textData() const {
@ -97,126 +104,80 @@ QByteArray ReadPasswordJob::binaryData() const {
return d->data;
}
QString ReadPasswordJob::key() const {
QString Job::key() const {
return d->key;
}
void ReadPasswordJob::setKey( const QString& key ) {
d->key = key;
}
void ReadPasswordJob::doStart() {
JobExecutor::instance()->enqueue( this );
void Job::setKey( const QString& key_ ) {
d->key = key_;
}
WritePasswordJob::WritePasswordJob( const QString& service, QObject* parent )
: Job( service, parent )
, d( new WritePasswordJobPrivate( this ) ) {
: Job( new WritePasswordJobPrivate( service, this ), parent ) {
}
WritePasswordJob::~WritePasswordJob() {
delete d;
}
QString WritePasswordJob::key() const {
return d->key;
}
void WritePasswordJob::setKey( const QString& key ) {
d->key = key;
}
void WritePasswordJob::setBinaryData( const QByteArray& data ) {
d->binaryData = data;
d->mode = WritePasswordJobPrivate::Binary;
d->data = data;
d->mode = JobPrivate::Binary;
}
void WritePasswordJob::setTextData( const QString& data ) {
d->textData = data;
d->mode = WritePasswordJobPrivate::Text;
}
void WritePasswordJob::doStart() {
JobExecutor::instance()->enqueue( this );
d->data = data.toUtf8();
d->mode = JobPrivate::Text;
}
DeletePasswordJob::DeletePasswordJob( const QString& service, QObject* parent )
: Job( service, parent )
, d( new DeletePasswordJobPrivate( this ) ) {
: Job( new DeletePasswordJobPrivate( service, this ), parent ) {
}
DeletePasswordJob::~DeletePasswordJob() {
delete d;
}
void DeletePasswordJob::doStart() {
//Internally, to delete a password we just execute a write job with no data set (null byte array).
//In all current implementations, this deletes the entry so this is sufficient
WritePasswordJob* job = new WritePasswordJob( service(), this );
connect( job, SIGNAL(finished(QKeychain::Job*)), d, SLOT(jobFinished(QKeychain::Job*)) );
job->setInsecureFallback(true);
job->setSettings(settings());
job->setKey( d->key );
job->doStart();
}
DeletePasswordJobPrivate::DeletePasswordJobPrivate(const QString &service_, DeletePasswordJob *qq) :
JobPrivate(service_, qq) {
QString DeletePasswordJob::key() const {
return d->key;
}
void DeletePasswordJob::setKey( const QString& key ) {
d->key = key;
}
void DeletePasswordJobPrivate::jobFinished( Job* job ) {
q->setError( job->error() );
q->setErrorString( job->errorString() );
q->emitFinished();
}
JobExecutor::JobExecutor()
: QObject( 0 )
, m_runningJob( 0 )
{
, m_jobRunning( false ) {
}
void JobExecutor::enqueue( Job* job ) {
m_queue.append( job );
m_queue.enqueue( job );
startNextIfNoneRunning();
}
void JobExecutor::startNextIfNoneRunning() {
if ( m_queue.isEmpty() || m_runningJob )
if ( m_queue.isEmpty() || m_jobRunning )
return;
QPointer<Job> next;
while ( !next && !m_queue.isEmpty() ) {
next = m_queue.first();
m_queue.pop_front();
next = m_queue.dequeue();
}
if ( next ) {
connect( next, SIGNAL(finished(QKeychain::Job*)), this, SLOT(jobFinished(QKeychain::Job*)) );
connect( next, SIGNAL(destroyed(QObject*)), this, SLOT(jobDestroyed(QObject*)) );
m_runningJob = next;
if ( ReadPasswordJob* rpj = qobject_cast<ReadPasswordJob*>( m_runningJob ) )
rpj->d->scheduledStart();
else if ( WritePasswordJob* wpj = qobject_cast<WritePasswordJob*>( m_runningJob) )
wpj->d->scheduledStart();
m_jobRunning = true;
next->scheduledStart();
}
}
void JobExecutor::jobDestroyed( QObject* object ) {
Job* job = static_cast<Job*>(object);
Q_UNUSED( object ) // for release mode
Q_ASSERT( object == m_runningJob );
m_runningJob->disconnect( this );
m_runningJob = 0;
job->disconnect( this );
m_jobRunning = false;
startNextIfNoneRunning();
}
void JobExecutor::jobFinished( Job* job ) {
Q_UNUSED( job ) // for release mode
Q_ASSERT( job == m_runningJob );
m_runningJob->disconnect( this );
m_runningJob = 0;
job->disconnect( this );
m_jobRunning = false;
startNextIfNoneRunning();
}
@ -227,3 +188,47 @@ JobExecutor* JobExecutor::instance() {
s_instance = new JobExecutor;
return s_instance;
}
ReadPasswordJobPrivate::ReadPasswordJobPrivate(const QString &service_, ReadPasswordJob *qq) :
JobPrivate(service_, qq) {
}
JobPrivate::JobPrivate(const QString &service_, Job *qq)
: error( NoError )
, service( service_ )
, autoDelete( true )
, insecureFallback( false )
, q(qq) {
}
QString JobPrivate::modeToString(Mode m)
{
switch (m) {
case Text:
return QLatin1String("Text");
case Binary:
return QLatin1String("Binary");
}
Q_ASSERT_X(false, Q_FUNC_INFO, "Unhandled Mode value");
return QString();
}
JobPrivate::Mode JobPrivate::stringToMode(const QString& s)
{
if (s == QLatin1String("Text") || s == QLatin1String("1"))
return Text;
if (s == QLatin1String("Binary") || s == QLatin1String("2"))
return Binary;
qCritical("Unexpected mode string '%s'", qPrintable(s));
return Text;
}
WritePasswordJobPrivate::WritePasswordJobPrivate(const QString &service_, WritePasswordJob *qq) :
JobPrivate(service_, qq) {
}

View File

@ -39,8 +39,7 @@ class JobPrivate;
class QKEYCHAIN_EXPORT Job : public QObject {
Q_OBJECT
public:
explicit Job( const QString& service, QObject* parent=0 );
public:
~Job();
QSettings* settings() const;
@ -59,19 +58,32 @@ public:
bool insecureFallback() const;
void setInsecureFallback( bool insecureFallback );
QString key() const;
void setKey( const QString& key );
Q_SIGNALS:
void finished( QKeychain::Job* );
protected:
Q_INVOKABLE virtual void doStart() = 0;
explicit Job( JobPrivate *q, QObject* parent=0 );
Q_INVOKABLE void doStart();
private:
void setError( Error error );
void setErrorString( const QString& errorString );
void emitFinished();
void emitFinishedWithError(Error, const QString& errorString);
private:
void scheduledStart();
protected:
JobPrivate* const d;
friend class JobExecutor;
friend class JobPrivate;
friend class ReadPasswordJobPrivate;
friend class WritePasswordJobPrivate;
friend class DeletePasswordJobPrivate;
};
class ReadPasswordJobPrivate;
@ -82,19 +94,11 @@ public:
explicit ReadPasswordJob( const QString& service, QObject* parent=0 );
~ReadPasswordJob();
QString key() const;
void setKey( const QString& key );
QByteArray binaryData() const;
QString textData() const;
protected:
void doStart();
private:
friend class QKeychain::ReadPasswordJobPrivate;
friend class QKeychain::JobExecutor;
ReadPasswordJobPrivate* const d;
};
class WritePasswordJobPrivate;
@ -105,20 +109,12 @@ public:
explicit WritePasswordJob( const QString& service, QObject* parent=0 );
~WritePasswordJob();
QString key() const;
void setKey( const QString& key );
void setBinaryData( const QByteArray& data );
void setTextData( const QString& data );
protected:
void doStart();
private:
friend class QKeychain::JobExecutor;
friend class QKeychain::WritePasswordJobPrivate;
friend class DeletePasswordJob;
WritePasswordJobPrivate* const d;
};
class DeletePasswordJobPrivate;
@ -129,15 +125,8 @@ public:
explicit DeletePasswordJob( const QString& service, QObject* parent=0 );
~DeletePasswordJob();
QString key() const;
void setKey( const QString& key );
protected:
void doStart();
private:
friend class QKeychain::DeletePasswordJobPrivate;
DeletePasswordJobPrivate* const d;
};
} // namespace QtKeychain

View File

@ -29,9 +29,9 @@ static QString strForStatus( OSStatus os ) {
const char * const buf = CFStringGetCStringPtr( str.value, kCFStringEncodingUTF8 );
if ( !buf )
return QObject::tr( "%1 (OSStatus %2)" )
.arg( "OSX Keychain Error" ).arg( os );
.arg( "OSX Keychain Error" ).arg( os );
return QObject::tr( "%1 (OSStatus %2)" )
.arg( QString::fromUtf8( buf, strlen( buf ) ) ).arg( os );
.arg( QString::fromUtf8( buf, strlen( buf ) ) ).arg( os );
}
static OSStatus readPw( QByteArray* pw,
@ -148,14 +148,17 @@ void WritePasswordJobPrivate::scheduledStart()
QString errorString;
Error error = NoError;
if ( mode == Delete ) {
const Error derr = deleteEntryImpl( q->service(), key, &errorString );
if ( derr != NoError )
error = CouldNotDeleteEntry;
q->emitFinishedWithError( error, errorString );
return;
}
const QByteArray data = mode == Text ? textData.toUtf8() : binaryData;
error = writeEntryImpl( q->service(), key, data, &errorString );
q->emitFinishedWithError( error, errorString );
}
void DeletePasswordJobPrivate::scheduledStart()
{
QString errorString;
Error error = NoError;
const Error derr = deleteEntryImpl( q->service(), key, &errorString );
if ( derr != NoError )
error = CouldNotDeleteEntry;
q->emitFinishedWithError( error, errorString );
}

View File

@ -13,7 +13,7 @@
#include <QObject>
#include <QPointer>
#include <QSettings>
#include <QVector>
#include <QQueue>
#if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN)
@ -35,105 +35,108 @@ class JobExecutor;
class JobPrivate : public QObject {
Q_OBJECT
public:
JobPrivate( const QString& service_ )
: error( NoError )
, service( service_ )
, autoDelete( true )
, insecureFallback( false ) {}
enum Mode {
Text,
Binary
};
virtual void scheduledStart() = 0;
static QString modeToString(Mode m);
static Mode stringToMode(const QString& s);
Mode mode;
#if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN)
org::kde::KWallet* iface;
int walletHandle;
static void gnomeKeyring_readCb( int result, const char* string, JobPrivate* data );
static void gnomeKeyring_writeCb( int result, JobPrivate* self );
virtual void fallbackOnError(const QDBusError& err) = 0;
protected Q_SLOTS:
void kwalletWalletFound( QDBusPendingCallWatcher* watcher );
virtual void kwalletFinished( QDBusPendingCallWatcher* watcher );
virtual void kwalletOpenFinished( QDBusPendingCallWatcher* watcher );
#else
void kwalletWalletFound(QDBusPendingCallWatcher *watcher) {}
virtual void kwalletFinished( QDBusPendingCallWatcher* watcher ) {}
virtual void kwalletOpenFinished( QDBusPendingCallWatcher* watcher ) {}
#endif
protected:
JobPrivate( const QString& service_, Job *q );
protected:
QKeychain::Error error;
QString errorString;
QString service;
bool autoDelete;
bool insecureFallback;
QPointer<QSettings> settings;
QString key;
Job* const q;
QByteArray data;
friend class Job;
friend class JobExecutor;
friend class ReadPasswordJob;
friend class WritePasswordJob;
};
class ReadPasswordJobPrivate : public QObject {
class ReadPasswordJobPrivate : public JobPrivate {
Q_OBJECT
public:
explicit ReadPasswordJobPrivate( ReadPasswordJob* qq ) : q( qq ), walletHandle( 0 ), dataType( Text ) {}
explicit ReadPasswordJobPrivate( const QString &service_, ReadPasswordJob* qq );
void scheduledStart();
ReadPasswordJob* const q;
QByteArray data;
QString key;
int walletHandle;
enum DataType {
Binary,
Text
};
DataType dataType;
#if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN)
org::kde::KWallet* iface;
static void gnomeKeyring_cb( int result, const char* string, ReadPasswordJobPrivate* data );
friend class QKeychain::JobExecutor;
void fallbackOnError(const QDBusError& err);
private Q_SLOTS:
void kwalletWalletFound( QDBusPendingCallWatcher* watcher );
void kwalletOpenFinished( QDBusPendingCallWatcher* watcher );
void kwalletEntryTypeFinished( QDBusPendingCallWatcher* watcher );
void kwalletReadFinished( QDBusPendingCallWatcher* watcher );
void kwalletFinished( QDBusPendingCallWatcher* watcher );
#else //moc's too dumb to respect above macros, so just define empty slot implementations
private Q_SLOTS:
void kwalletWalletFound( QDBusPendingCallWatcher* ) {}
void kwalletOpenFinished( QDBusPendingCallWatcher* ) {}
void kwalletEntryTypeFinished( QDBusPendingCallWatcher* ) {}
void kwalletReadFinished( QDBusPendingCallWatcher* ) {}
void kwalletFinished( QDBusPendingCallWatcher* ) {}
#endif
friend class ReadPasswordJob;
};
class WritePasswordJobPrivate : public QObject {
class WritePasswordJobPrivate : public JobPrivate {
Q_OBJECT
public:
explicit WritePasswordJobPrivate( WritePasswordJob* qq ) : q( qq ), mode( Delete ) {}
explicit WritePasswordJobPrivate( const QString &service_, WritePasswordJob* qq );
void scheduledStart();
enum Mode {
Delete,
Text,
Binary
};
static QString modeToString(Mode m);
static Mode stringToMode(const QString& s);
WritePasswordJob* const q;
Mode mode;
QString key;
QByteArray binaryData;
QString textData;
#if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN)
org::kde::KWallet* iface;
static void gnomeKeyring_cb( int result, WritePasswordJobPrivate* self );
friend class QKeychain::JobExecutor;
void fallbackOnError(const QDBusError& err);
private Q_SLOTS:
void kwalletWalletFound( QDBusPendingCallWatcher* watcher );
void kwalletOpenFinished( QDBusPendingCallWatcher* watcher );
void kwalletWriteFinished( QDBusPendingCallWatcher* watcher );
#else
private Q_SLOTS:
void kwalletWalletFound( QDBusPendingCallWatcher* ) {}
void kwalletOpenFinished( QDBusPendingCallWatcher* ) {}
void kwalletWriteFinished( QDBusPendingCallWatcher* ) {}
#endif
friend class WritePasswordJob;
};
class DeletePasswordJobPrivate : public QObject {
class DeletePasswordJobPrivate : public JobPrivate {
Q_OBJECT
public:
explicit DeletePasswordJobPrivate( DeletePasswordJob* qq ) : q( qq ) {}
explicit DeletePasswordJobPrivate( const QString &service_, DeletePasswordJob* qq );
void scheduledStart();
#if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN)
void fallbackOnError(const QDBusError& err);
#endif
protected:
void doStart();
DeletePasswordJob* const q;
QString key;
private Q_SLOTS:
void jobFinished( QKeychain::Job* );
friend class DeletePasswordJob;
};
class JobExecutor : public QObject {
@ -154,8 +157,8 @@ private Q_SLOTS:
private:
static JobExecutor* s_instance;
Job* m_runningJob;
QVector<QPointer<Job> > m_queue;
QQueue<QPointer<Job> > m_queue;
bool m_jobRunning;
};
}

View File

@ -94,7 +94,7 @@ static KeyringBackend detectKeyringBackend()
case DesktopEnv_Plasma5:
return Backend_Kwallet5;
break;
// fall through
// fall through
case DesktopEnv_Gnome:
case DesktopEnv_Unity:
case DesktopEnv_Xfce:
@ -125,7 +125,7 @@ static void kwalletReadPasswordScheduledStartImpl(const char * service, const ch
}
else
{
// D-Bus is not reachable so none can tell us something about KWalletd
// D-Bus is not reachable so none can tell us something about KWalletd
QDBusError err( QDBusError::NoServer, ReadPasswordJobPrivate::tr("D-Bus is not running") );
priv->fallbackOnError( err );
}
@ -135,7 +135,7 @@ void ReadPasswordJobPrivate::scheduledStart() {
switch ( getKeyringBackend() ) {
case Backend_GnomeKeyring:
if ( !GnomeKeyring::find_network_password( key.toUtf8().constData(), q->service().toUtf8().constData(),
reinterpret_cast<GnomeKeyring::OperationGetStringCallback>( &ReadPasswordJobPrivate::gnomeKeyring_cb ),
reinterpret_cast<GnomeKeyring::OperationGetStringCallback>( &JobPrivate::gnomeKeyring_readCb ),
this, 0 ) )
q->emitFinishedWithError( OtherError, tr("Unknown error") );
break;
@ -149,13 +149,14 @@ void ReadPasswordJobPrivate::scheduledStart() {
}
}
void ReadPasswordJobPrivate::kwalletWalletFound(QDBusPendingCallWatcher *watcher)
void JobPrivate::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*)) );
connect( pendingWatcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
this, SLOT(kwalletOpenFinished(QDBusPendingCallWatcher*)) );
}
static QPair<Error, QString> mapGnomeKeyringError( int result )
@ -188,10 +189,10 @@ static QPair<Error, QString> mapGnomeKeyringError( int result )
return qMakePair( OtherError, QObject::tr("Unknown error") );
}
void ReadPasswordJobPrivate::gnomeKeyring_cb( int result, const char* string, ReadPasswordJobPrivate* self )
void JobPrivate::gnomeKeyring_readCb( int result, const char* string, JobPrivate* self )
{
if ( result == GnomeKeyring::RESULT_OK ) {
if ( self->dataType == ReadPasswordJobPrivate::Text )
if ( self->mode == JobPrivate::Text )
self->data = string;
else
self->data = QByteArray::fromBase64( string );
@ -209,11 +210,7 @@ void ReadPasswordJobPrivate::fallbackOnError(const QDBusError& err )
if ( q->insecureFallback() && actual->contains( dataKey( key ) ) ) {
const WritePasswordJobPrivate::Mode mode = WritePasswordJobPrivate::stringToMode( actual->value( typeKey( key ) ).toString() );
if (mode == WritePasswordJobPrivate::Binary)
dataType = Binary;
else
dataType = Text;
mode = JobPrivate::stringToMode( actual->value( typeKey( key ) ).toString() );
data = actual->value( dataKey( key ) ).toByteArray();
q->emitFinished();
@ -300,10 +297,10 @@ void ReadPasswordJobPrivate::kwalletEntryTypeFinished( QDBusPendingCallWatcher*
q->emitFinishedWithError( EntryNotFound, tr("Entry not found") );
return;
case Password:
dataType = Text;
mode = Text;
break;
case Stream:
dataType = Binary;
mode = Binary;
break;
case Map:
q->emitFinishedWithError( EntryNotFound, tr("Unsupported entry type 'Map'") );
@ -313,32 +310,28 @@ void ReadPasswordJobPrivate::kwalletEntryTypeFinished( QDBusPendingCallWatcher*
return;
}
const QDBusPendingCall nextReply = dataType == Text
? QDBusPendingCall( iface->readPassword( walletHandle, q->service(), key, q->service() ) )
: QDBusPendingCall( iface->readEntry( walletHandle, q->service(), key, q->service() ) );
const QDBusPendingCall nextReply = (mode == 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*)) );
}
void ReadPasswordJobPrivate::kwalletReadFinished( QDBusPendingCallWatcher* watcher ) {
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 ) {
void ReadPasswordJobPrivate::kwalletFinished( QDBusPendingCallWatcher* watcher ) {
if ( !watcher->isError() ) {
if ( mode == Binary ) {
QDBusPendingReply<QByteArray> reply = *watcher;
data = reply.value();
} else {
QDBusPendingReply<QString> reply = *watcher;
data = reply.value().toUtf8();
}
q->emitFinished();
}
JobPrivate::kwalletFinished(watcher);
}
static void kwalletWritePasswordScheduledStart( const char * service, const char * path, WritePasswordJobPrivate * priv ) {
static void kwalletWritePasswordScheduledStart( const char * service, const char * path, JobPrivate * priv ) {
if ( QDBusConnection::sessionBus().isConnected() )
{
priv->iface = new org::kde::KWallet( QLatin1String(service), QLatin1String(path), QDBusConnection::sessionBus(), priv );
@ -356,21 +349,15 @@ static void kwalletWritePasswordScheduledStart( const char * service, const char
void WritePasswordJobPrivate::scheduledStart() {
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 ),
this, 0 ) )
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 ),
this, 0 ) )
q->emitFinishedWithError( OtherError, tr("Unknown error") );
}
case Backend_GnomeKeyring: {
QByteArray password = (mode == JobPrivate::Text) ? data : data.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>( &JobPrivate::gnomeKeyring_writeCb ),
this, 0 ) )
q->emitFinishedWithError( OtherError, tr("Unknown error") );
}
break;
case Backend_Kwallet4:
@ -382,35 +369,6 @@ void WritePasswordJobPrivate::scheduledStart() {
}
}
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;
qCritical("Unexpected mode string '%s'", qPrintable(s));
return Text;
}
void WritePasswordJobPrivate::fallbackOnError(const QDBusError &err)
{
QScopedPointer<QSettings> local( !q->settings() ? new QSettings( q->service() ) : 0 );
@ -421,25 +379,14 @@ void WritePasswordJobPrivate::fallbackOnError(const QDBusError &err)
return;
}
if ( mode == Delete ) {
actual->remove( key );
actual->sync();
q->emitFinished();
return;
}
actual->setValue( QString::fromLatin1( "%1/type" ).arg( key ), mode );
if ( mode == Text )
actual->setValue( QString::fromLatin1( "%1/data" ).arg( key ), textData.toUtf8() );
else if ( mode == Binary )
actual->setValue( QString::fromLatin1( "%1/data" ).arg( key ), binaryData );
actual->setValue( QString::fromLatin1( "%1/data" ).arg( key ), data );
actual->sync();
q->emitFinished();
}
void WritePasswordJobPrivate::gnomeKeyring_cb( int result, WritePasswordJobPrivate* self )
void JobPrivate::gnomeKeyring_writeCb(int result, JobPrivate* self )
{
if ( result == GnomeKeyring::RESULT_OK ) {
self->q->emitFinished();
@ -449,16 +396,7 @@ void WritePasswordJobPrivate::gnomeKeyring_cb( int result, WritePasswordJobPriva
}
}
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*)) );
}
void WritePasswordJobPrivate::kwalletOpenFinished( QDBusPendingCallWatcher* watcher ) {
void JobPrivate::kwalletOpenFinished( QDBusPendingCallWatcher* watcher ) {
watcher->deleteLater();
QDBusPendingReply<int> reply = *watcher;
@ -486,10 +424,10 @@ void WritePasswordJobPrivate::kwalletOpenFinished( QDBusPendingCallWatcher* watc
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() );
if ( mode == Text )
nextReply = iface->writePassword( handle, q->service(), key, QString::fromUtf8(data), q->service() );
else if ( mode == Binary )
nextReply = iface->writeEntry( handle, q->service(), key, data, q->service() );
else
nextReply = iface->removeEntry( handle, q->service(), key, q->service() );
@ -497,14 +435,54 @@ void WritePasswordJobPrivate::kwalletOpenFinished( QDBusPendingCallWatcher* watc
connect( nextWatcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(kwalletWriteFinished(QDBusPendingCallWatcher*)) );
}
void WritePasswordJobPrivate::kwalletWriteFinished( QDBusPendingCallWatcher* watcher ) {
void JobPrivate::kwalletFinished( QDBusPendingCallWatcher* watcher ) {
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() ) );
q->emitFinishedWithError( OtherError, tr("Could not open wallet: %1; %2")
.arg( QDBusError::errorString( err.type() ), err.message() ) );
return;
}
q->emitFinished();
}
void DeletePasswordJobPrivate::scheduledStart() {
switch ( getKeyringBackend() ) {
case Backend_GnomeKeyring: {
if ( !GnomeKeyring::delete_network_password(
key.toUtf8().constData(), q->service().toUtf8().constData(),
reinterpret_cast<GnomeKeyring::OperationDoneCallback>( &JobPrivate::gnomeKeyring_writeCb ),
this, 0 ) )
q->emitFinishedWithError( OtherError, tr("Unknown error") );
}
break;
case Backend_Kwallet4:
kwalletWritePasswordScheduledStart("org.kde.kwalletd", "/modules/kwalletd", this);
break;
case Backend_Kwallet5:
kwalletWritePasswordScheduledStart("org.kde.kwalletd5", "/modules/kwalletd5", this);
break;
}
}
void DeletePasswordJobPrivate::fallbackOnError(const QDBusError &err) {
QScopedPointer<QSettings> local( !q->settings() ? new QSettings( q->service() ) : 0 );
QSettings* actual = q->settings() ? q->settings() : local.data();
if ( !q->insecureFallback() ) {
q->emitFinishedWithError( OtherError, tr("Could not open wallet: %1; %2")
.arg( QDBusError::errorString( err.type() ), err.message() ) );
return;
}
actual->remove( key );
actual->sync();
q->emitFinished();
q->emitFinished();
}

View File

@ -17,6 +17,82 @@
using namespace QKeychain;
#if defined(USE_CREDENTIAL_STORE)
#include <wincred.h>
void ReadPasswordJobPrivate::scheduledStart() {
std::wstring name = key.toStdWString();
//Use settings member if there, create local settings object if not
std::auto_ptr<QSettings> local( !q->settings() ? new QSettings( q->service() ) : 0 );
PCREDENTIALW cred;
if (!CredReadW(name.c_str(), CRED_TYPE_GENERIC, 0, &cred)) {
Error error;
QString msg;
switch(GetLastError()) {
case ERROR_NOT_FOUND:
error = EntryNotFound;
msg = tr("Password entry not found");
break;
default:
error = OtherError;
msg = tr("Could not decrypt data");
break;
}
q->emitFinishedWithError( error, msg );
return;
}
data = QByteArray((char*)cred->CredentialBlob, cred->CredentialBlobSize);
CredFree(cred);
q->emitFinished();
}
void WritePasswordJobPrivate::scheduledStart() {
CREDENTIALW cred;
char *pwd = data.data();
std::wstring name = key.toStdWString();
memset(&cred, 0, sizeof(cred));
cred.Comment = L"QtKeychain";
cred.Type = CRED_TYPE_GENERIC;
cred.TargetName = (LPWSTR)name.c_str();
cred.CredentialBlobSize = data.size();
cred.CredentialBlob = (LPBYTE)pwd;
cred.Persist = CRED_PERSIST_LOCAL_MACHINE;
if (!CredWriteW(&cred, 0)) {
q->emitFinishedWithError( OtherError, tr("Encryption failed") ); //TODO more details available?
} else {
q->emitFinished();
}
}
void DeletePasswordJobPrivate::scheduledStart() {
std::wstring name = key.toStdWString();
if (!CredDeleteW(name.c_str(), CRED_TYPE_GENERIC, 0)) {
Error error;
QString msg;
switch(GetLastError()) {
case ERROR_NOT_FOUND:
error = EntryNotFound;
msg = tr("Password entry not found");
break;
default:
error = OtherError;
msg = tr("Could not decrypt data");
break;
}
q->emitFinishedWithError( error, msg );
} else {
q->emitFinished();
}
}
#else
void ReadPasswordJobPrivate::scheduledStart() {
//Use settings member if there, create local settings object if not
std::auto_ptr<QSettings> local( !q->settings() ? new QSettings( q->service() ) : 0 );
@ -53,24 +129,6 @@ void ReadPasswordJobPrivate::scheduledStart() {
}
void WritePasswordJobPrivate::scheduledStart() {
if ( mode == Delete ) {
//Use settings member if there, create local settings object if not
std::auto_ptr<QSettings> local( !q->settings() ? new QSettings( q->service() ) : 0 );
QSettings* actual = q->settings() ? q->settings() : local.get();
actual->remove( key );
actual->sync();
if ( actual->status() != QSettings::NoError ) {
const QString err = actual->status() == QSettings::AccessError
? tr("Could not delete encrypted data from settings: access error")
: tr("Could not delete encrypted data from settings: format error");
q->emitFinishedWithError( OtherError, err );
} else {
q->emitFinished();
}
return;
}
QByteArray data = mode == Binary ? binaryData : textData.toUtf8();
DATA_BLOB blob_in, blob_out;
blob_in.pbData = reinterpret_cast<BYTE*>( data.data() );
blob_in.cbData = data.size();
@ -105,3 +163,20 @@ void WritePasswordJobPrivate::scheduledStart() {
q->emitFinished();
}
void DeletePasswordJobPrivate::scheduledStart() {
//Use settings member if there, create local settings object if not
std::auto_ptr<QSettings> local( !q->settings() ? new QSettings( q->service() ) : 0 );
QSettings* actual = q->settings() ? q->settings() : local.get();
actual->remove( key );
actual->sync();
if ( actual->status() != QSettings::NoError ) {
const QString err = actual->status() == QSettings::AccessError
? tr("Could not delete encrypted data from settings: access error")
: tr("Could not delete encrypted data from settings: format error");
q->emitFinishedWithError( OtherError, err );
} else {
q->emitFinished();
}
}
#endif