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:
Andrius Štikonas 2018-07-15 00:09:39 +01:00
parent 65ef6ab83d
commit 51780a6297
5 changed files with 94 additions and 5 deletions

View File

@ -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)

View File

@ -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();
}

View File

@ -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();

View File

@ -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);

View File

@ -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>