Stop KAuth helper if application crashes.
This is implemented by pinging application from KAuth helper via DBus. If it is busy then KAuth helper also waits for the current job to finish.
This commit is contained in:
parent
65ef6ab83d
commit
51780a6297
|
@ -34,6 +34,7 @@ target_link_libraries(kpmcore_externalcommand
|
|||
|
||||
install(TARGETS kpmcore_externalcommand DESTINATION ${KAUTH_HELPER_INSTALL_DIR})
|
||||
install( FILES util/org.kde.kpmcore.helperinterface.conf DESTINATION ${SYSCONF_INSTALL_DIR}/dbus-1/system.d )
|
||||
install( FILES util/org.kde.kpmcore.applicationinterface.conf DESTINATION ${SYSCONF_INSTALL_DIR}/dbus-1/system.d )
|
||||
|
||||
kauth_install_helper_files(kpmcore_externalcommand org.kde.kpmcore.externalcommand root)
|
||||
kauth_install_actions(org.kde.kpmcore.externalcommand util/org.kde.kpmcore.externalcommand.actions)
|
||||
|
|
|
@ -22,10 +22,12 @@
|
|||
#include "core/copytarget.h"
|
||||
#include "core/copysourcedevice.h"
|
||||
#include "core/copytargetdevice.h"
|
||||
#include "util/globallog.h"
|
||||
#include "util/externalcommand.h"
|
||||
#include "util/report.h"
|
||||
|
||||
#include <QCryptographicHash>
|
||||
#include <QDBusConnection>
|
||||
#include <QDBusInterface>
|
||||
#include <QDBusReply>
|
||||
#include <QEventLoop>
|
||||
|
@ -51,6 +53,7 @@ struct ExternalCommandPrivate
|
|||
int m_ExitCode;
|
||||
QByteArray m_Output;
|
||||
QByteArray m_Input;
|
||||
DBusThread *m_thread;
|
||||
};
|
||||
|
||||
unsigned int ExternalCommand::counter = 0;
|
||||
|
@ -75,7 +78,8 @@ ExternalCommand::ExternalCommand(const QString& cmd, const QStringList& args, co
|
|||
d->m_Output = QByteArray();
|
||||
|
||||
if (!helperStarted)
|
||||
startHelper();
|
||||
if(!startHelper())
|
||||
Log(Log::Level::error) << xi18nc("@info:status", "Could not obtain administrator privileges.");
|
||||
|
||||
setup(processChannelMode);
|
||||
}
|
||||
|
@ -346,6 +350,13 @@ void ExternalCommand::setExitCode(int i)
|
|||
|
||||
bool ExternalCommand::startHelper()
|
||||
{
|
||||
if (!QDBusConnection::systemBus().isConnected()) {
|
||||
qWarning() << "Could not connect to DBus session bus";
|
||||
return false;
|
||||
}
|
||||
d->m_thread = new DBusThread;
|
||||
d->m_thread->start();
|
||||
|
||||
init = new QCA::Initializer;
|
||||
// Generate RSA key pair for signing external command requests
|
||||
if (!QCA::isSupported("pkey") || !QCA::PKey::supportedIOTypes().contains(QCA::PKey::RSA)) {
|
||||
|
@ -402,3 +413,18 @@ void ExternalCommand::stopHelper()
|
|||
delete privateKey;
|
||||
delete init;
|
||||
}
|
||||
|
||||
void DBusThread::run()
|
||||
{
|
||||
if (!QDBusConnection::systemBus().registerService(QStringLiteral("org.kde.kpmcore.applicationinterface"))) {
|
||||
qWarning() << QDBusConnection::systemBus().lastError().message();
|
||||
return;
|
||||
}
|
||||
if (!QDBusConnection::systemBus().registerObject(QStringLiteral("/Application"), this, QDBusConnection::ExportAllSlots)) {
|
||||
qWarning() << QDBusConnection::systemBus().lastError().message();
|
||||
return;
|
||||
}
|
||||
|
||||
QEventLoop loop;
|
||||
loop.exec();
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QtGlobal>
|
||||
#include <QThread>
|
||||
#include <QVariant>
|
||||
|
||||
#include <memory>
|
||||
|
@ -38,6 +39,16 @@ class CopySource;
|
|||
class CopyTarget;
|
||||
struct ExternalCommandPrivate;
|
||||
|
||||
class DBusThread : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_CLASSINFO("D-Bus Interface", "org.kde.kpmcore.ping")
|
||||
void run() override;
|
||||
|
||||
public Q_SLOTS:
|
||||
Q_SCRIPTABLE void ping() {return;};
|
||||
};
|
||||
|
||||
/** An external command.
|
||||
|
||||
Runs an external command as a child process.
|
||||
|
@ -94,7 +105,7 @@ public:
|
|||
|
||||
// KAuth
|
||||
/**< start ExternalCommand Helper */
|
||||
static bool startHelper();
|
||||
bool startHelper();
|
||||
|
||||
/**< stop ExternalCommand Helper */
|
||||
static void stopHelper();
|
||||
|
|
|
@ -27,6 +27,18 @@
|
|||
#include <KLocalizedString>
|
||||
|
||||
/** Initialize ExternalCommandHelper Daemon and prepare DBus interface
|
||||
*
|
||||
* KAuth helper runs in the background until application exits.
|
||||
* To avoid forever running helper in case of application crash
|
||||
* ExternalCommand class opens DBus interface that we ping.
|
||||
* If helper is not busy than it exits when ping fails. Otherwise,
|
||||
* we wait for the current job to finish before exiting, so even in case
|
||||
* of main application crash, we do not leave partially moved data.
|
||||
*
|
||||
* This helper also starts another DBus interface where it listens to
|
||||
* command execution requests from the application that started the helper.
|
||||
* These requests are validated using public key cryptography, to prevent
|
||||
* other unprivileged applications from gaining root privileges.
|
||||
*/
|
||||
ActionReply ExternalCommandHelper::init(const QVariantMap& args)
|
||||
{
|
||||
|
@ -36,17 +48,42 @@ ActionReply ExternalCommandHelper::init(const QVariantMap& args)
|
|||
reply.addData(QStringLiteral("success"), false);
|
||||
return reply;
|
||||
}
|
||||
m_publicKey = QCA::PublicKey::fromDER(args[QStringLiteral("pubkey")].toByteArray());
|
||||
m_Counter = 0;
|
||||
|
||||
if (!QDBusConnection::systemBus().registerService(QStringLiteral("org.kde.kpmcore.helperinterface"))) {
|
||||
qWarning() << QDBusConnection::systemBus().lastError().message();
|
||||
reply.addData(QStringLiteral("success"), false);
|
||||
return reply;
|
||||
}
|
||||
QDBusConnection::systemBus().registerObject(QStringLiteral("/Helper"), this, QDBusConnection::ExportAllSlots);
|
||||
if (!QDBusConnection::systemBus().registerObject(QStringLiteral("/Helper"), this, QDBusConnection::ExportAllSlots)) {
|
||||
qWarning() << QDBusConnection::systemBus().lastError().message();
|
||||
reply.addData(QStringLiteral("success"), false);
|
||||
return reply;
|
||||
}
|
||||
|
||||
m_publicKey = QCA::PublicKey::fromDER(args[QStringLiteral("pubkey")].toByteArray());
|
||||
m_Counter = 0;
|
||||
|
||||
HelperSupport::progressStep(QVariantMap());
|
||||
auto timeout = [this] () {
|
||||
QDBusInterface iface(QStringLiteral("org.kde.kpmcore.applicationinterface"),
|
||||
QStringLiteral("/Application"),
|
||||
QStringLiteral("org.kde.kpmcore.ping"),
|
||||
QDBusConnection::systemBus());
|
||||
iface.setTimeout(5000); // 5 seconds;
|
||||
auto pcall = iface.asyncCall(QStringLiteral("ping"));
|
||||
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pcall, this);
|
||||
auto exitLoop = [&] (QDBusPendingCallWatcher *watcher) {
|
||||
if (watcher->isError()) {
|
||||
qWarning() << watcher->error();
|
||||
m_loop.exit();
|
||||
}
|
||||
};
|
||||
connect(watcher, &QDBusPendingCallWatcher::finished, exitLoop);
|
||||
};
|
||||
|
||||
QTimer *timer = new QTimer(this);
|
||||
connect(timer, &QTimer::timeout, this, timeout);
|
||||
timer->start(5000); // 5 seconds
|
||||
m_loop.exec();
|
||||
reply.addData(QStringLiteral("success"), true);
|
||||
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
<!DOCTYPE busconfig PUBLIC
|
||||
"-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
|
||||
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
|
||||
<busconfig>
|
||||
|
||||
<policy context="default">
|
||||
<allow own="org.kde.kpmcore.applicationinterface"/>
|
||||
</policy>
|
||||
|
||||
<policy user="root">
|
||||
<allow send_destination="org.kde.kpmcore.applicationinterface"
|
||||
send_interface="org.kde.kpmcore.ping"/>
|
||||
</policy>
|
||||
</busconfig>
|
Loading…
Reference in New Issue