Move KAuth helper setup code to ExternalCommand class.
Delay helper startup until it is actually required.
This commit is contained in:
parent
ed59aac2c8
commit
145f54f18c
|
@ -21,16 +21,10 @@
|
|||
#include "backend/corebackend.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QCryptographicHash>
|
||||
#include <QDebug>
|
||||
#include <QDBusInterface>
|
||||
#include <QStringList>
|
||||
#include <QString>
|
||||
#include <QVector>
|
||||
|
||||
#include <QtCrypto>
|
||||
|
||||
#include <KAuth>
|
||||
#include <KLocalizedString>
|
||||
#include <KPluginFactory>
|
||||
#include <KPluginLoader>
|
||||
|
@ -38,18 +32,16 @@
|
|||
|
||||
struct CoreBackendManagerPrivate
|
||||
{
|
||||
KAuth::ExecuteJob *m_job;
|
||||
CoreBackend *m_Backend;
|
||||
|
||||
QCA::Initializer init;
|
||||
QCA::PrivateKey privateKey;
|
||||
unsigned int counter = 0;
|
||||
};
|
||||
|
||||
CoreBackendManager::CoreBackendManager() :
|
||||
d(std::make_unique<CoreBackendManagerPrivate>())
|
||||
{
|
||||
startExternalCommandHelper();
|
||||
}
|
||||
|
||||
CoreBackendManager::~CoreBackendManager()
|
||||
{
|
||||
}
|
||||
|
||||
CoreBackendManager* CoreBackendManager::self()
|
||||
|
@ -78,63 +70,6 @@ QVector<KPluginMetaData> CoreBackendManager::list() const
|
|||
return KPluginLoader::findPlugins(QString(), filter);
|
||||
}
|
||||
|
||||
bool CoreBackendManager::startExternalCommandHelper()
|
||||
{
|
||||
// Generate RSA key pair for signing external command requests
|
||||
if (!QCA::isSupported("pkey") || !QCA::PKey::supportedIOTypes().contains(QCA::PKey::RSA)) {
|
||||
qCritical() << xi18n("QCA does not support RSA.");
|
||||
return false;
|
||||
}
|
||||
|
||||
d->privateKey = QCA::KeyGenerator().createRSA(4096);
|
||||
if(d->privateKey.isNull()) {
|
||||
qCritical() << xi18n("Failed to make private RSA key.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!d->privateKey.canSign()) {
|
||||
qCritical() << xi18n("Generated key cannot be used for signatures.");
|
||||
return false;
|
||||
}
|
||||
|
||||
QCA::PublicKey pubkey = d->privateKey.toPublicKey();
|
||||
|
||||
KAuth::Action action = KAuth::Action(QStringLiteral("org.kde.kpmcore.externalcommand.init"));
|
||||
action.setHelperId(QStringLiteral("org.kde.kpmcore.externalcommand"));
|
||||
action.setTimeout(10 * 24 * 3600 * 1000); // 10 days
|
||||
QVariantMap arguments;
|
||||
arguments.insert(QStringLiteral("pubkey"), pubkey.toDER());
|
||||
action.setArguments(arguments);
|
||||
d->m_job = action.execute();
|
||||
job()->start();
|
||||
|
||||
// Wait until ExternalCommand Helper is ready (helper sends newData signal just before it enters event loop)
|
||||
QEventLoop loop;
|
||||
auto exitLoop = [&] () { loop.exit(); };
|
||||
auto conn = QObject::connect(job(), &KAuth::ExecuteJob::newData, exitLoop);
|
||||
QObject::connect(job(), &KJob::finished, [=] () { if(d->m_job->error()) exitLoop(); } );
|
||||
loop.exec();
|
||||
QObject::disconnect(conn);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CoreBackendManager::stopExternalCommandHelper()
|
||||
{
|
||||
QDBusInterface iface(QStringLiteral("org.kde.kpmcore.helperinterface"), QStringLiteral("/Helper"), QStringLiteral("org.kde.kpmcore.externalcommand"), QDBusConnection::systemBus());
|
||||
if (iface.isValid()) {
|
||||
QByteArray request;
|
||||
request.setNum(++CoreBackendManager::self()->counter());
|
||||
QByteArray hash = QCryptographicHash::hash(request, QCryptographicHash::Sha512);
|
||||
iface.call(QStringLiteral("exit"), d->privateKey.signMessage(hash, QCA::EMSA3_Raw));
|
||||
}
|
||||
}
|
||||
|
||||
KAuth::ExecuteJob* CoreBackendManager::job()
|
||||
{
|
||||
return d->m_job;
|
||||
}
|
||||
|
||||
bool CoreBackendManager::load(const QString& name)
|
||||
{
|
||||
if (backend())
|
||||
|
@ -168,13 +103,3 @@ bool CoreBackendManager::load(const QString& name)
|
|||
void CoreBackendManager::unload()
|
||||
{
|
||||
}
|
||||
|
||||
QCA::PrivateKey CoreBackendManager::privateKey()
|
||||
{
|
||||
return d->privateKey;
|
||||
}
|
||||
|
||||
unsigned int& CoreBackendManager::counter()
|
||||
{
|
||||
return d->counter;
|
||||
}
|
||||
|
|
|
@ -17,22 +17,18 @@
|
|||
*************************************************************************/
|
||||
|
||||
#ifndef KPMCORE_COREBACKENDMANAGER_H
|
||||
|
||||
#define KPMCORE_COREBACKENDMANAGER_H
|
||||
|
||||
#include "util/libpartitionmanagerexport.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <QObject>
|
||||
#include <QVector>
|
||||
|
||||
class QString;
|
||||
class QStringList;
|
||||
class KPluginMetaData;
|
||||
class CoreBackend;
|
||||
namespace KAuth { class ExecuteJob; }
|
||||
namespace QCA { class PrivateKey; }
|
||||
struct CoreBackendManagerPrivate;
|
||||
|
||||
/**
|
||||
|
@ -44,8 +40,8 @@ struct CoreBackendManagerPrivate;
|
|||
*/
|
||||
class LIBKPMCORE_EXPORT CoreBackendManager
|
||||
{
|
||||
private:
|
||||
CoreBackendManager();
|
||||
~CoreBackendManager();
|
||||
|
||||
public:
|
||||
/**
|
||||
|
@ -82,24 +78,6 @@ public:
|
|||
*/
|
||||
CoreBackend* backend();
|
||||
|
||||
/**
|
||||
* @return a pointer to the KAuth job
|
||||
*/
|
||||
KAuth::ExecuteJob* job();
|
||||
|
||||
/**
|
||||
* stop ExternalCommand Helper
|
||||
*/
|
||||
void stopExternalCommandHelper();
|
||||
|
||||
/**< @return RSA private key used for signing External Command requests. */
|
||||
QCA::PrivateKey privateKey();
|
||||
|
||||
unsigned int& counter();
|
||||
|
||||
private:
|
||||
bool startExternalCommandHelper();
|
||||
|
||||
private:
|
||||
std::unique_ptr<CoreBackendManagerPrivate> d;
|
||||
};
|
||||
|
|
|
@ -53,6 +53,12 @@ struct ExternalCommandPrivate
|
|||
QByteArray m_Input;
|
||||
};
|
||||
|
||||
unsigned int ExternalCommand::counter = 0;
|
||||
KAuth::ExecuteJob* ExternalCommand::m_job;
|
||||
QCA::PrivateKey* ExternalCommand::privateKey;
|
||||
QCA::Initializer* ExternalCommand::init;
|
||||
bool ExternalCommand::helperStarted = false;
|
||||
|
||||
/** Creates a new ExternalCommand instance without Report.
|
||||
@param cmd the command to run
|
||||
@param args the arguments to pass to the command
|
||||
|
@ -66,6 +72,9 @@ ExternalCommand::ExternalCommand(const QString& cmd, const QStringList& args, co
|
|||
d->m_ExitCode = -1;
|
||||
d->m_Output = QByteArray();
|
||||
|
||||
if (!helperStarted)
|
||||
startHelper();
|
||||
|
||||
setup(processChannelMode);
|
||||
}
|
||||
|
||||
|
@ -130,7 +139,7 @@ bool ExternalCommand::start(int timeout)
|
|||
if (iface.isValid()) {
|
||||
QByteArray request;
|
||||
|
||||
request.setNum(++CoreBackendManager::self()->counter());
|
||||
request.setNum(++counter);
|
||||
request.append(cmd.toUtf8());
|
||||
for (const auto &argument : qAsConst(d->m_Args))
|
||||
request.append(argument.toUtf8());
|
||||
|
@ -139,7 +148,7 @@ bool ExternalCommand::start(int timeout)
|
|||
QByteArray hash = QCryptographicHash::hash(request, QCryptographicHash::Sha512);
|
||||
|
||||
QDBusPendingCall pcall = iface.asyncCall(QStringLiteral("start"),
|
||||
CoreBackendManager::self()->privateKey().signMessage(hash, QCA::EMSA3_Raw),
|
||||
privateKey->signMessage(hash, QCA::EMSA3_Raw),
|
||||
cmd,
|
||||
args(),
|
||||
d->m_Input);
|
||||
|
@ -180,15 +189,15 @@ bool ExternalCommand::copyBlocks(CopySource& source, CopyTarget& target)
|
|||
}
|
||||
|
||||
// TODO KF6:Use new signal-slot syntax
|
||||
connect(CoreBackendManager::self()->job(), SIGNAL(percent(KJob*, unsigned long)), this, SLOT(emitProgress(KJob*, unsigned long)));
|
||||
connect(CoreBackendManager::self()->job(), &KAuth::ExecuteJob::newData, this, &ExternalCommand::emitReport);
|
||||
connect(m_job, SIGNAL(percent(KJob*, unsigned long)), this, SLOT(emitProgress(KJob*, unsigned long)));
|
||||
connect(m_job, &KAuth::ExecuteJob::newData, this, &ExternalCommand::emitReport);
|
||||
|
||||
QDBusInterface iface(QStringLiteral("org.kde.kpmcore.helperinterface"), QStringLiteral("/Helper"), QStringLiteral("org.kde.kpmcore.externalcommand"), QDBusConnection::systemBus());
|
||||
iface.setTimeout(10 * 24 * 3600 * 1000); // 10 days
|
||||
if (iface.isValid()) {
|
||||
QByteArray request;
|
||||
|
||||
request.setNum(++CoreBackendManager::self()->counter());
|
||||
request.setNum(++counter);
|
||||
request.append(source.path().toUtf8());
|
||||
request.append(QByteArray::number(source.firstByte()));
|
||||
request.append(QByteArray::number(source.length()));
|
||||
|
@ -200,7 +209,7 @@ bool ExternalCommand::copyBlocks(CopySource& source, CopyTarget& target)
|
|||
|
||||
// Use asynchronous DBus calls, so that we can process reports and progress
|
||||
QDBusPendingCall pcall= iface.asyncCall(QStringLiteral("copyblocks"),
|
||||
CoreBackendManager::self()->privateKey().signMessage(hash, QCA::EMSA3_Raw),
|
||||
privateKey->signMessage(hash, QCA::EMSA3_Raw),
|
||||
source.path(), source.firstByte(), source.length(),
|
||||
target.path(), target.firstByte(), blockSize);
|
||||
|
||||
|
@ -332,3 +341,61 @@ void ExternalCommand::setExitCode(int i)
|
|||
{
|
||||
d->m_ExitCode = i;
|
||||
}
|
||||
|
||||
bool ExternalCommand::startHelper()
|
||||
{
|
||||
init = new QCA::Initializer;
|
||||
// Generate RSA key pair for signing external command requests
|
||||
if (!QCA::isSupported("pkey") || !QCA::PKey::supportedIOTypes().contains(QCA::PKey::RSA)) {
|
||||
qCritical() << xi18n("QCA does not support RSA.");
|
||||
return false;
|
||||
}
|
||||
|
||||
privateKey = new QCA::PrivateKey;
|
||||
*privateKey = QCA::KeyGenerator().createRSA(4096);
|
||||
if(privateKey->isNull()) {
|
||||
qCritical() << xi18n("Failed to make private RSA key.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!privateKey->canSign()) {
|
||||
qCritical() << xi18n("Generated key cannot be used for signatures.");
|
||||
return false;
|
||||
}
|
||||
|
||||
QCA::PublicKey pubkey = privateKey->toPublicKey();
|
||||
|
||||
KAuth::Action action = KAuth::Action(QStringLiteral("org.kde.kpmcore.externalcommand.init"));
|
||||
action.setHelperId(QStringLiteral("org.kde.kpmcore.externalcommand"));
|
||||
action.setTimeout(10 * 24 * 3600 * 1000); // 10 days
|
||||
QVariantMap arguments;
|
||||
arguments.insert(QStringLiteral("pubkey"), pubkey.toDER());
|
||||
action.setArguments(arguments);
|
||||
m_job = action.execute();
|
||||
m_job->start();
|
||||
|
||||
// Wait until ExternalCommand Helper is ready (helper sends newData signal just before it enters event loop)
|
||||
QEventLoop loop;
|
||||
auto exitLoop = [&] () { loop.exit(); };
|
||||
auto conn = QObject::connect(m_job, &KAuth::ExecuteJob::newData, exitLoop);
|
||||
QObject::connect(m_job, &KJob::finished, [=] () { if(m_job->error()) exitLoop(); } );
|
||||
loop.exec();
|
||||
QObject::disconnect(conn);
|
||||
|
||||
helperStarted = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void ExternalCommand::stopHelper()
|
||||
{
|
||||
QDBusInterface iface(QStringLiteral("org.kde.kpmcore.helperinterface"), QStringLiteral("/Helper"), QStringLiteral("org.kde.kpmcore.externalcommand"), QDBusConnection::systemBus());
|
||||
if (iface.isValid()) {
|
||||
QByteArray request;
|
||||
request.setNum(++counter);
|
||||
QByteArray hash = QCryptographicHash::hash(request, QCryptographicHash::Sha512);
|
||||
iface.call(QStringLiteral("exit"), privateKey->signMessage(hash, QCA::EMSA3_Raw));
|
||||
}
|
||||
|
||||
delete privateKey;
|
||||
delete init;
|
||||
}
|
||||
|
|
|
@ -20,8 +20,6 @@
|
|||
#define KPMCORE_EXTERNALCOMMAND_H
|
||||
|
||||
#include "util/libpartitionmanagerexport.h"
|
||||
#include "core/copysourcedevice.h"
|
||||
#include "core/copytargetfile.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QProcess>
|
||||
|
@ -33,7 +31,11 @@
|
|||
#include <memory>
|
||||
|
||||
class KJob;
|
||||
namespace KAuth { class ExecuteJob; }
|
||||
namespace QCA { class PrivateKey; class Initializer; }
|
||||
class Report;
|
||||
class CopySource;
|
||||
class CopyTarget;
|
||||
struct ExternalCommandPrivate;
|
||||
|
||||
/** An external command.
|
||||
|
@ -90,6 +92,13 @@ public:
|
|||
|
||||
void emitReport(const QVariantMap& report) { emit reportSignal(report); }
|
||||
|
||||
// KAuth
|
||||
/**< start ExternalCommand Helper */
|
||||
static bool startHelper();
|
||||
|
||||
/**< stop ExternalCommand Helper */
|
||||
static void stopHelper();
|
||||
|
||||
Q_SIGNALS:
|
||||
void progress(int);
|
||||
void reportSignal(const QVariantMap&);
|
||||
|
@ -97,7 +106,7 @@ Q_SIGNALS:
|
|||
public Q_SLOTS:
|
||||
void emitProgress(KJob*, unsigned long percent) { emit progress(percent); };
|
||||
|
||||
protected:
|
||||
private:
|
||||
void setExitCode(int i);
|
||||
void setup(const QProcess::ProcessChannelMode processChannelMode);
|
||||
|
||||
|
@ -106,6 +115,13 @@ protected:
|
|||
|
||||
private:
|
||||
std::unique_ptr<ExternalCommandPrivate> d;
|
||||
|
||||
// KAuth stuff
|
||||
static unsigned int counter;
|
||||
static KAuth::ExecuteJob *m_job;
|
||||
static QCA::Initializer *init;
|
||||
static QCA::PrivateKey *privateKey;
|
||||
static bool helperStarted;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "helpers.h"
|
||||
|
||||
#include "backend/corebackendmanager.h"
|
||||
#include "util/externalcommand.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QString>
|
||||
|
@ -59,5 +60,5 @@ KPMCoreInitializer::KPMCoreInitializer( const char* backend ) : KPMCoreInitializ
|
|||
|
||||
KPMCoreInitializer::~KPMCoreInitializer()
|
||||
{
|
||||
CoreBackendManager::self()->stopExternalCommandHelper();
|
||||
ExternalCommand::stopHelper();
|
||||
}
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
#include <QDebug>
|
||||
#include <QList>
|
||||
|
||||
#include <memory>
|
||||
|
||||
using PartitionList = QList<Partition *>;
|
||||
|
||||
// Recursive helper for flatten(), adds partitions that
|
||||
|
@ -65,16 +67,18 @@ PartitionList flatten(PartitionTable *table)
|
|||
int main( int argc, char **argv )
|
||||
{
|
||||
QCoreApplication app(argc, argv);
|
||||
std::unique_ptr<KPMCoreInitializer> i;
|
||||
|
||||
if (argc != 2)
|
||||
{
|
||||
KPMCoreInitializer i;
|
||||
if (!i.isValid())
|
||||
i = std::make_unique<KPMCoreInitializer>();
|
||||
if (!i->isValid())
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
KPMCoreInitializer i( argv[1] );
|
||||
if (!i.isValid())
|
||||
i = std::make_unique<KPMCoreInitializer>( argv[1] );
|
||||
if (!i->isValid())
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -112,6 +116,5 @@ int main( int argc, char **argv )
|
|||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,8 @@
|
|||
#include <QDebug>
|
||||
#include <QList>
|
||||
|
||||
#include <memory>
|
||||
|
||||
using PartitionList = QList<Partition *>;
|
||||
|
||||
// Recursive helper for flatten(), adds partitions that
|
||||
|
@ -62,17 +64,18 @@ PartitionList flatten(PartitionTable *table)
|
|||
int main( int argc, char **argv )
|
||||
{
|
||||
QCoreApplication app(argc, argv);
|
||||
std::unique_ptr<KPMCoreInitializer> i;
|
||||
|
||||
if (argc != 2)
|
||||
{
|
||||
KPMCoreInitializer i;
|
||||
if (!i.isValid())
|
||||
i = std::make_unique<KPMCoreInitializer>();
|
||||
if (!i->isValid())
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
KPMCoreInitializer i( argv[1] );
|
||||
if (!i.isValid())
|
||||
i = std::make_unique<KPMCoreInitializer>( argv[1] );
|
||||
if (!i->isValid())
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -105,6 +108,5 @@ int main( int argc, char **argv )
|
|||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue