diff --git a/autotests/TestBackend.cpp b/autotests/TestBackend.cpp index 4650524..85a14ec 100644 --- a/autotests/TestBackend.cpp +++ b/autotests/TestBackend.cpp @@ -1,120 +1,122 @@ /* * Copyright (C) 2012 Dario Freddi * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * 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. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . */ #include "TestBackend.h" #include namespace KAuth { TestBackend::TestBackend() : AuthBackend() { qDebug() << "Test backend loaded"; setCapabilities(AuthorizeFromHelperCapability | CheckActionExistenceCapability); } void TestBackend::setNewCapabilities(AuthBackend::Capabilities capabilities) { qDebug() << "Capabilities changing"; setCapabilities(capabilities); } Action::AuthStatus TestBackend::authorizeAction(const QString &action) { if (action == QLatin1String("doomed.to.fail")) { return Action::DeniedStatus; } return Action::AuthorizedStatus; } void TestBackend::setupAction(const QString &action) { if (action == QLatin1String("doomed.to.fail")) { m_actionStatuses.insert(action, Action::DeniedStatus); } else if (action == QLatin1String("requires.auth") || action == QLatin1String("generates.error")) { m_actionStatuses.insert(action, Action::AuthRequiredStatus); } else if (action == QLatin1String("always.authorized")) { m_actionStatuses.insert(action, Action::AuthorizedStatus); } else if (action.startsWith(QLatin1String("org.kde.kf5auth.autotest"))) { m_actionStatuses.insert(action, Action::AuthRequiredStatus); } } Action::AuthStatus TestBackend::actionStatus(const QString &action) { if (m_actionStatuses.contains(action)) { return m_actionStatuses.value(action); } return Action::InvalidStatus; } QByteArray TestBackend::callerID() const { return QByteArray("a random caller Id"); } -bool TestBackend::isCallerAuthorized(const QString &action, QByteArray callerId) +bool TestBackend::isCallerAuthorized(const QString &action, const QByteArray &callerId, const QVariantMap &details) { + Q_UNUSED(details); + if (action == QLatin1String("doomed.to.fail")) { return false; } else if (action == QLatin1String("requires.auth")) { m_actionStatuses.insert(action, Action::AuthorizedStatus); emit actionStatusChanged(action, Action::AuthorizedStatus); return true; } else if (action == QLatin1String("generates.error")) { m_actionStatuses.insert(action, Action::ErrorStatus); emit actionStatusChanged(action, Action::ErrorStatus); return false; } else if (action == QLatin1String("always.authorized")) { return true; } else if (action.startsWith(QLatin1String("org.kde.kf5auth.autotest"))) { qDebug() << "Caller ID:" << callerId; if (callerId == callerID()) { m_actionStatuses.insert(action, Action::AuthorizedStatus); emit actionStatusChanged(action, Action::AuthorizedStatus); return true; } else { m_actionStatuses.insert(action, Action::DeniedStatus); emit actionStatusChanged(action, Action::DeniedStatus); } } return false; } bool TestBackend::actionExists(const QString &action) { qDebug() << "Checking if action " << action << "exists"; if (action != QLatin1String("doomed.to.fail") && action != QLatin1String("requires.auth") && action != QLatin1String("generates.error") && action != QLatin1String("always.authorized") && action != QLatin1String("/safinvalid124%$&") && !action.startsWith(QLatin1String("org.kde.kf5auth.autotest"))) { return false; } return true; } } // namespace Auth diff --git a/autotests/TestBackend.h b/autotests/TestBackend.h index 86c2e00..e590c34 100644 --- a/autotests/TestBackend.h +++ b/autotests/TestBackend.h @@ -1,54 +1,54 @@ /* * Copyright (C) 2012 Dario Freddi * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * 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. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . */ #ifndef TEST_BACKEND_H #define TEST_BACKEND_H #include "AuthBackend.h" #include class QByteArray; namespace KAuth { class TestBackend : public AuthBackend { Q_OBJECT Q_INTERFACES(KAuth::AuthBackend) public: TestBackend(); void setupAction(const QString &) override; Action::AuthStatus authorizeAction(const QString &) override; Action::AuthStatus actionStatus(const QString &) override; QByteArray callerID() const override; - bool isCallerAuthorized(const QString &action, QByteArray callerID) override; + bool isCallerAuthorized(const QString &action, const QByteArray &callerID, const QVariantMap &details) override; bool actionExists(const QString &action) override; public Q_SLOTS: void setNewCapabilities(KAuth::AuthBackend::Capabilities capabilities); private: QHash m_actionStatuses; }; } // namespace Auth #endif diff --git a/src/AuthBackend.cpp b/src/AuthBackend.cpp index a847494..c9edab5 100644 --- a/src/AuthBackend.cpp +++ b/src/AuthBackend.cpp @@ -1,75 +1,81 @@ /* * Copyright (C) 2008 Nicola Gigante * Copyright (C) 2010 Dario Freddi * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * 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. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . */ #include "AuthBackend.h" namespace KAuth { class AuthBackend::Private { public: Private() {} virtual ~Private() {} Capabilities capabilities; }; AuthBackend::AuthBackend() : QObject(nullptr) , d(new Private) { } AuthBackend::~AuthBackend() { delete d; } AuthBackend::Capabilities AuthBackend::capabilities() const { return d->capabilities; } void AuthBackend::setCapabilities(AuthBackend::Capabilities capabilities) { d->capabilities = capabilities; } AuthBackend::ExtraCallerIDVerificationMethod AuthBackend::extraCallerIDVerificationMethod() const { return NoExtraCallerIDVerificationMethod; } bool AuthBackend::actionExists(const QString &action) { Q_UNUSED(action); return false; } void AuthBackend::preAuthAction(const QString &action, QWidget *parent) { Q_UNUSED(action) Q_UNUSED(parent) } +QVariantMap AuthBackend::backendDetails(const DetailsMap &details) +{ + Q_UNUSED(details); + return QVariantMap(); +} + } //namespace KAuth diff --git a/src/AuthBackend.h b/src/AuthBackend.h index 09195ef..139786e 100644 --- a/src/AuthBackend.h +++ b/src/AuthBackend.h @@ -1,81 +1,84 @@ /* * Copyright (C) 2008 Nicola Gigante * Copyright (C) 2009-2010 Dario Freddi * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * 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. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . */ #ifndef AUTH_BACKEND_H #define AUTH_BACKEND_H #include #include "kauthaction.h" namespace KAuth { +typedef Action::DetailsMap DetailsMap; + class AuthBackend : public QObject { Q_OBJECT Q_DISABLE_COPY(AuthBackend) public: enum Capability { NoCapability = 0, AuthorizeFromClientCapability = 1, AuthorizeFromHelperCapability = 2, CheckActionExistenceCapability = 4, PreAuthActionCapability = 8 }; Q_DECLARE_FLAGS(Capabilities, Capability) enum ExtraCallerIDVerificationMethod { NoExtraCallerIDVerificationMethod, VerifyAgainstDBusServiceName, VerifyAgainstDBusServicePid, }; AuthBackend(); virtual ~AuthBackend(); virtual void setupAction(const QString &action) = 0; virtual void preAuthAction(const QString &action, QWidget *parent); virtual Action::AuthStatus authorizeAction(const QString &action) = 0; virtual Action::AuthStatus actionStatus(const QString &action) = 0; virtual QByteArray callerID() const = 0; virtual ExtraCallerIDVerificationMethod extraCallerIDVerificationMethod() const; - virtual bool isCallerAuthorized(const QString &action, QByteArray callerID) = 0; + virtual bool isCallerAuthorized(const QString &action, const QByteArray &callerID, const QVariantMap &details) = 0; virtual bool actionExists(const QString &action); + virtual QVariantMap backendDetails(const DetailsMap &details); Capabilities capabilities() const; protected: void setCapabilities(Capabilities capabilities); Q_SIGNALS: void actionStatusChanged(const QString &action, KAuth::Action::AuthStatus status); private: class Private; Private *const d; }; } // namespace Auth Q_DECLARE_INTERFACE(KAuth::AuthBackend, "org.kde.kf5auth.AuthBackend/0.1") Q_DECLARE_OPERATORS_FOR_FLAGS(KAuth::AuthBackend::Capabilities) #endif diff --git a/src/HelperProxy.h b/src/HelperProxy.h index a33273e..06b0c29 100644 --- a/src/HelperProxy.h +++ b/src/HelperProxy.h @@ -1,65 +1,68 @@ /* * Copyright (C) 2008 Nicola Gigante * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * 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. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . */ #ifndef HELPER_PROXY_H #define HELPER_PROXY_H #include #include #include #include #include "kauthaction.h" #include "kauthactionreply.h" namespace KAuth { +typedef Action::DetailsMap DetailsMap; + class HelperProxy : public QObject { Q_OBJECT public: virtual ~HelperProxy(); // Application-side methods virtual void executeAction(const QString &action, const QString &helperID, - const QVariantMap &arguments, int timeout) = 0; + const DetailsMap &details, const QVariantMap &arguments, + int timeout) = 0; virtual void stopAction(const QString &action, const QString &helperID) = 0; // Helper-side methods virtual bool initHelper(const QString &name) = 0; virtual void setHelperResponder(QObject *o) = 0; virtual bool hasToStopAction() = 0; virtual void sendDebugMessage(int level, const char *msg) = 0; virtual void sendProgressStep(int step) = 0; virtual void sendProgressStep(const QVariantMap &step) = 0; Q_SIGNALS: void actionStarted(const QString &action); void actionPerformed(const QString &action, const KAuth::ActionReply &reply); void progressStep(const QString &action, int progress); void progressStep(const QString &action, const QVariantMap &data); }; } // namespace KAuth Q_DECLARE_INTERFACE(KAuth::HelperProxy, "org.kde.kf5auth.HelperProxy/0.1") #endif diff --git a/src/backends/dbus/DBusHelperProxy.cpp b/src/backends/dbus/DBusHelperProxy.cpp index 8f0d336..b372b94 100644 --- a/src/backends/dbus/DBusHelperProxy.cpp +++ b/src/backends/dbus/DBusHelperProxy.cpp @@ -1,336 +1,345 @@ /* * Copyright (C) 2008 Nicola Gigante * Copyright (C) 2009-2010 Dario Freddi * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * 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. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . */ #include "DBusHelperProxy.h" #include #include #include #include #include #include #include "BackendsManager.h" #include "kf5authadaptor.h" #include "kauthdebug.h" extern Q_CORE_EXPORT const QMetaTypeInterface *qMetaTypeGuiHelper; namespace KAuth { static void debugMessageReceived(int t, const QString &message); DBusHelperProxy::DBusHelperProxy() : responder(nullptr) , m_stopRequest(false) , m_busConnection(QDBusConnection::systemBus()) { } DBusHelperProxy::DBusHelperProxy(const QDBusConnection &busConnection) : responder(nullptr) , m_stopRequest(false) , m_busConnection(busConnection) { } DBusHelperProxy::~DBusHelperProxy() { } void DBusHelperProxy::stopAction(const QString &action, const QString &helperID) { QDBusMessage message; message = QDBusMessage::createMethodCall(helperID, QLatin1String("/"), QLatin1String("org.kde.kf5auth"), QLatin1String("stopAction")); QList args; args << action; message.setArguments(args); m_busConnection.asyncCall(message); } -void DBusHelperProxy::executeAction(const QString &action, const QString &helperID, const QVariantMap &arguments, int timeout) +void DBusHelperProxy::executeAction(const QString &action, const QString &helperID, const DetailsMap &details, const QVariantMap &arguments, int timeout) { QByteArray blob; { QDataStream stream(&blob, QIODevice::WriteOnly); stream << arguments; } //on unit tests we won't have a service, but the service will already be running const auto reply = m_busConnection.interface()->startService(helperID); if (!reply.isValid() && !m_busConnection.interface()->isServiceRegistered(helperID)) { ActionReply errorReply = ActionReply::DBusErrorReply(); errorReply.setErrorDescription(tr("DBus Backend error: service start %1 failed: %2").arg(helperID, reply.error().message())); emit actionPerformed(action, errorReply); return; } const bool connected = m_busConnection.connect(helperID, QLatin1String("/"), QLatin1String("org.kde.kf5auth"), QLatin1String("remoteSignal"), this, SLOT(remoteSignalReceived(int,QString,QByteArray))); //if already connected reply will be false but we won't have an error or a reason to fail if (!connected && m_busConnection.lastError().isValid()) { ActionReply errorReply = ActionReply::DBusErrorReply(); errorReply.setErrorDescription(tr("DBus Backend error: connection to helper failed. %1\n(application: %2 helper: %3)").arg( m_busConnection.lastError().message(), qApp->applicationName(), helperID)); emit actionPerformed(action, errorReply); return; } QDBusMessage message; message = QDBusMessage::createMethodCall(helperID, QLatin1String("/"), QLatin1String("org.kde.kf5auth"), QLatin1String("performAction")); QList args; - args << action << BackendsManager::authBackend()->callerID() << blob; + args << action << BackendsManager::authBackend()->callerID() << BackendsManager::authBackend()->backendDetails(details) << blob; message.setArguments(args); m_actionsInProgress.push_back(action); QDBusPendingCall pendingCall = m_busConnection.asyncCall(message, timeout); auto watcher = new QDBusPendingCallWatcher(pendingCall, this); - connect(watcher, &QDBusPendingCallWatcher::finished, this, [this, action, watcher]() { + connect(watcher, &QDBusPendingCallWatcher::finished, this, [=] () mutable { watcher->deleteLater(); - const QDBusMessage reply = watcher->reply(); + QDBusMessage reply = watcher->reply(); if (reply.type() == QDBusMessage::ErrorMessage) { + if (watcher->error().type() == QDBusError::InvalidArgs) { + // For backwards compatibility if helper binary was built with older KAuth version. + args.removeAt(args.count() - 2); // remove backend details + message.setArguments(args); + reply = m_busConnection.call(message, QDBus::Block, timeout); + if (reply.type() != QDBusMessage::ErrorMessage) { + return; + } + } ActionReply r = ActionReply::DBusErrorReply(); r.setErrorDescription(tr("DBus Backend error: could not contact the helper. " "Connection error: %1. Message error: %2").arg(reply.errorMessage(), m_busConnection.lastError().message())); qCWarning(KAUTH) << reply.errorMessage(); emit actionPerformed(action, r); } }); } bool DBusHelperProxy::initHelper(const QString &name) { new Kf5authAdaptor(this); if (!m_busConnection.registerService(name)) { qCWarning(KAUTH) << "Error registering helper DBus service" << name << m_busConnection.lastError().message(); return false; } if (!m_busConnection.registerObject(QLatin1String("/"), this)) { qCWarning(KAUTH) << "Error registering helper DBus object:" << m_busConnection.lastError().message(); return false; } m_name = name; return true; } void DBusHelperProxy::setHelperResponder(QObject *o) { responder = o; } void DBusHelperProxy::remoteSignalReceived(int t, const QString &action, QByteArray blob) { SignalType type = static_cast(t); QDataStream stream(&blob, QIODevice::ReadOnly); if (type == ActionStarted) { emit actionStarted(action); } else if (type == ActionPerformed) { ActionReply reply = ActionReply::deserialize(blob); m_actionsInProgress.removeOne(action); emit actionPerformed(action, reply); } else if (type == DebugMessage) { int level; QString message; stream >> level >> message; debugMessageReceived(level, message); } else if (type == ProgressStepIndicator) { int step; stream >> step; emit progressStep(action, step); } else if (type == ProgressStepData) { QVariantMap data; stream >> data; emit progressStep(action, data); } } void DBusHelperProxy::stopAction(const QString &action) { Q_UNUSED(action) //#warning FIXME: The stop request should be action-specific rather than global m_stopRequest = true; } bool DBusHelperProxy::hasToStopAction() { QEventLoop loop; loop.processEvents(QEventLoop::AllEvents); return m_stopRequest; } -bool DBusHelperProxy::isCallerAuthorized(const QString &action, const QByteArray &callerID) +bool DBusHelperProxy::isCallerAuthorized(const QString &action, const QByteArray &callerID, const QVariantMap &details) { // Check the caller is really who it says it is switch (BackendsManager::authBackend()->extraCallerIDVerificationMethod()) { case AuthBackend::NoExtraCallerIDVerificationMethod: break; case AuthBackend::VerifyAgainstDBusServiceName: if (message().service().toUtf8() != callerID) { return false; } break; case AuthBackend::VerifyAgainstDBusServicePid: if (connection().interface()->servicePid(message().service()).value() != callerID.toUInt()) { return false; } break; } - return BackendsManager::authBackend()->isCallerAuthorized(action, callerID); + return BackendsManager::authBackend()->isCallerAuthorized(action, callerID, details); } -QByteArray DBusHelperProxy::performAction(const QString &action, const QByteArray &callerID, QByteArray arguments) +QByteArray DBusHelperProxy::performAction(const QString &action, const QByteArray &callerID, const QVariantMap &details, QByteArray arguments) { if (!responder) { return ActionReply::NoResponderReply().serialized(); } if (!m_currentAction.isEmpty()) { return ActionReply::HelperBusyReply().serialized(); } // Make sure we don't try restoring gui variants, in particular QImage/QPixmap/QIcon are super dangerous // since they end up calling the image loaders and thus are a vector for crashing → executing code auto origMetaTypeGuiHelper = qMetaTypeGuiHelper; qMetaTypeGuiHelper = nullptr; QVariantMap args; QDataStream s(&arguments, QIODevice::ReadOnly); s >> args; qMetaTypeGuiHelper = origMetaTypeGuiHelper; m_currentAction = action; emit remoteSignal(ActionStarted, action, QByteArray()); QEventLoop e; e.processEvents(QEventLoop::AllEvents); ActionReply retVal; QTimer *timer = responder->property("__KAuth_Helper_Shutdown_Timer").value(); timer->stop(); - if (isCallerAuthorized(action, callerID)) { + if (isCallerAuthorized(action, callerID, details)) { QString slotname = action; if (slotname.startsWith(m_name + QLatin1Char('.'))) { slotname = slotname.right(slotname.length() - m_name.length() - 1); } slotname.replace(QLatin1Char('.'), QLatin1Char('_')); bool success = QMetaObject::invokeMethod(responder, slotname.toLatin1().data(), Qt::DirectConnection, Q_RETURN_ARG(ActionReply, retVal), Q_ARG(QVariantMap, args)); if (!success) { retVal = ActionReply::NoSuchActionReply(); } } else { retVal = ActionReply::AuthorizationDeniedReply(); } timer->start(); emit remoteSignal(ActionPerformed, action, retVal.serialized()); e.processEvents(QEventLoop::AllEvents); m_currentAction.clear(); m_stopRequest = false; return retVal.serialized(); } void DBusHelperProxy::sendDebugMessage(int level, const char *msg) { QByteArray blob; QDataStream stream(&blob, QIODevice::WriteOnly); stream << level << QString::fromLocal8Bit(msg); emit remoteSignal(DebugMessage, m_currentAction, blob); } void DBusHelperProxy::sendProgressStep(int step) { QByteArray blob; QDataStream stream(&blob, QIODevice::WriteOnly); stream << step; emit remoteSignal(ProgressStepIndicator, m_currentAction, blob); } void DBusHelperProxy::sendProgressStep(const QVariantMap &data) { QByteArray blob; QDataStream stream(&blob, QIODevice::WriteOnly); stream << data; emit remoteSignal(ProgressStepData, m_currentAction, blob); } void debugMessageReceived(int t, const QString &message) { QtMsgType type = static_cast(t); switch (type) { case QtDebugMsg: qDebug("Debug message from helper: %s", message.toLatin1().data()); break; case QtInfoMsg: qInfo("Info message from helper: %s", message.toLatin1().data()); break; case QtWarningMsg: qWarning("Warning from helper: %s", message.toLatin1().data()); break; case QtCriticalMsg: qCritical("Critical warning from helper: %s", message.toLatin1().data()); break; case QtFatalMsg: qFatal("Fatal error from helper: %s", message.toLatin1().data()); break; } } } // namespace Auth diff --git a/src/backends/dbus/DBusHelperProxy.h b/src/backends/dbus/DBusHelperProxy.h index e43190c..5cd2efe 100644 --- a/src/backends/dbus/DBusHelperProxy.h +++ b/src/backends/dbus/DBusHelperProxy.h @@ -1,88 +1,89 @@ /* * Copyright (C) 2008 Nicola Gigante * Copyright (C) 2009 Dario Freddi * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * 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. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . */ #ifndef DBUS_HELPER_PROXY_H #define DBUS_HELPER_PROXY_H #include "HelperProxy.h" #include "kauthactionreply.h" #include #include #include namespace KAuth { class DBusHelperProxy : public HelperProxy, protected QDBusContext { Q_OBJECT Q_PLUGIN_METADATA(IID "org.kde.DBusHelperProxy") Q_INTERFACES(KAuth::HelperProxy) QObject *responder; QString m_name; QString m_currentAction; bool m_stopRequest; QList m_actionsInProgress; QDBusConnection m_busConnection; enum SignalType { ActionStarted, // The blob argument is empty ActionPerformed, // The blob argument contains the ActionReply DebugMessage, // The blob argument contains the debug level and the message (in this order) ProgressStepIndicator, // The blob argument contains the step indicator ProgressStepData // The blob argument contains the QVariantMap }; public: DBusHelperProxy(); DBusHelperProxy(const QDBusConnection &busConnection); ~DBusHelperProxy() override; virtual void executeAction(const QString &action, const QString &helperID, - const QVariantMap &arguments, int timeout = -1) override; + const DetailsMap &details, const QVariantMap &arguments, + int timeout = -1) override; void stopAction(const QString &action, const QString &helperID) override; bool initHelper(const QString &name) override; void setHelperResponder(QObject *o) override; bool hasToStopAction() override; void sendDebugMessage(int level, const char *msg) override; void sendProgressStep(int step) override; void sendProgressStep(const QVariantMap &data) override; public Q_SLOTS: void stopAction(const QString &action); - QByteArray performAction(const QString &action, const QByteArray &callerID, QByteArray arguments); + QByteArray performAction(const QString &action, const QByteArray &callerID, const QVariantMap &details, QByteArray arguments); Q_SIGNALS: void remoteSignal(int type, const QString &action, const QByteArray &blob); // This signal is sent from the helper to the app private Q_SLOTS: void remoteSignalReceived(int type, const QString &action, QByteArray blob); private: - bool isCallerAuthorized(const QString &action, const QByteArray &callerID); + bool isCallerAuthorized(const QString &action, const QByteArray &callerID, const QVariantMap &details); }; } // namespace Auth #endif diff --git a/src/backends/dbus/org.kde.kf5auth.xml b/src/backends/dbus/org.kde.kf5auth.xml index 336ff05..3420773 100644 --- a/src/backends/dbus/org.kde.kf5auth.xml +++ b/src/backends/dbus/org.kde.kf5auth.xml @@ -1,20 +1,22 @@ + + diff --git a/src/backends/fake/FakeBackend.cpp b/src/backends/fake/FakeBackend.cpp index 6ca863c..022de89 100644 --- a/src/backends/fake/FakeBackend.cpp +++ b/src/backends/fake/FakeBackend.cpp @@ -1,60 +1,61 @@ /* * Copyright (C) 2008 Nicola Gigante * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * 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. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . */ #include "FakeBackend.h" namespace KAuth { FakeBackend::FakeBackend() : AuthBackend() { setCapabilities(NoCapability); } Action::AuthStatus FakeBackend::authorizeAction(const QString &action) { Q_UNUSED(action) return Action::DeniedStatus; } void FakeBackend::setupAction(const QString &action) { Q_UNUSED(action) } Action::AuthStatus FakeBackend::actionStatus(const QString &action) { Q_UNUSED(action) return Action::DeniedStatus; } QByteArray FakeBackend::callerID() const { return QByteArray(); } -bool FakeBackend::isCallerAuthorized(const QString &action, QByteArray callerID) +bool FakeBackend::isCallerAuthorized(const QString &action, const QByteArray &callerID, const QVariantMap &details) { Q_UNUSED(action) Q_UNUSED(callerID) + Q_UNUSED(details) return false; } } // namespace Auth diff --git a/src/backends/fake/FakeBackend.h b/src/backends/fake/FakeBackend.h index b62b687..9a0be1b 100644 --- a/src/backends/fake/FakeBackend.h +++ b/src/backends/fake/FakeBackend.h @@ -1,47 +1,47 @@ /* * Copyright (C) 2008 Nicola Gigante * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * 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. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . */ #ifndef FAKE_BACKEND_H #define FAKE_BACKEND_H #include "AuthBackend.h" #include class QByteArray; namespace KAuth { class FakeBackend : public AuthBackend { Q_OBJECT Q_INTERFACES(KAuth::AuthBackend) public: FakeBackend(); void setupAction(const QString &) override; Action::AuthStatus authorizeAction(const QString &) override; Action::AuthStatus actionStatus(const QString &) override; QByteArray callerID() const override; - bool isCallerAuthorized(const QString &action, QByteArray callerID) override; + bool isCallerAuthorized(const QString &action, const QByteArray &callerID, const QVariantMap &details) override; }; } // namespace Auth #endif diff --git a/src/backends/fakehelper/FakeHelperProxy.cpp b/src/backends/fakehelper/FakeHelperProxy.cpp index c78c0ac..69c039e 100644 --- a/src/backends/fakehelper/FakeHelperProxy.cpp +++ b/src/backends/fakehelper/FakeHelperProxy.cpp @@ -1,83 +1,84 @@ /* * Copyright (C) 2010 Dario Freddi * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * 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. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . */ #include "FakeHelperProxy.h" namespace KAuth { FakeHelperProxy::FakeHelperProxy() : HelperProxy() { } FakeHelperProxy::~FakeHelperProxy() { } void FakeHelperProxy::sendProgressStep(const QVariantMap &step) { Q_UNUSED(step) } void FakeHelperProxy::sendProgressStep(int step) { Q_UNUSED(step) } void FakeHelperProxy::sendDebugMessage(int level, const char *msg) { Q_UNUSED(level) Q_UNUSED(msg) } bool FakeHelperProxy::hasToStopAction() { return false; } void FakeHelperProxy::setHelperResponder(QObject *o) { Q_UNUSED(o) } bool FakeHelperProxy::initHelper(const QString &name) { Q_UNUSED(name) return false; } void FakeHelperProxy::stopAction(const QString &action, const QString &helperID) { Q_UNUSED(action) Q_UNUSED(helperID) } -void FakeHelperProxy::executeAction(const QString &action, const QString &helperID, const QVariantMap &arguments, int timeout) +void FakeHelperProxy::executeAction(const QString &action, const QString &helperID, const DetailsMap &details, const QVariantMap &arguments, int timeout) { Q_UNUSED(helperID) + Q_UNUSED(details) Q_UNUSED(arguments) Q_UNUSED(timeout) emit actionPerformed(action, KAuth::ActionReply::NoSuchActionReply()); } } diff --git a/src/backends/fakehelper/FakeHelperProxy.h b/src/backends/fakehelper/FakeHelperProxy.h index 4bc75e1..3003fb0 100644 --- a/src/backends/fakehelper/FakeHelperProxy.h +++ b/src/backends/fakehelper/FakeHelperProxy.h @@ -1,49 +1,49 @@ /* * Copyright (C) 2010 Dario Freddi * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * 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. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . */ #ifndef FAKEHELPERPROXY_H #define FAKEHELPERPROXY_H #include "HelperProxy.h" namespace KAuth { class FakeHelperProxy : public HelperProxy { Q_OBJECT Q_INTERFACES(KAuth::HelperProxy) public: FakeHelperProxy(); virtual ~FakeHelperProxy(); void sendProgressStep(const QVariantMap &step) override; void sendProgressStep(int step) override; void sendDebugMessage(int level, const char *msg) override; bool hasToStopAction() override; void setHelperResponder(QObject *o) override; bool initHelper(const QString &name) override; void stopAction(const QString &action, const QString &helperID) override; - void executeAction(const QString &action, const QString &helperID, const QVariantMap &arguments, int timeout = -1) override; + void executeAction(const QString &action, const QString &helperID, const DetailsMap &details, const QVariantMap &arguments, int timeout = -1) override; }; } #endif // FAKEHELPERPROXY_H diff --git a/src/backends/mac/AuthServicesBackend.cpp b/src/backends/mac/AuthServicesBackend.cpp index 5896591..77b7c85 100644 --- a/src/backends/mac/AuthServicesBackend.cpp +++ b/src/backends/mac/AuthServicesBackend.cpp @@ -1,197 +1,199 @@ /* * Copyright (C) 2008 Nicola Gigante * Copyright (C) 2014,2016 René Bertin * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * 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. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . */ #include "AuthServicesBackend.h" #include #include #include Q_DECLARE_LOGGING_CATEGORY(KAUTH_OSX) // logging category for this backend, default: log stuff >= warning Q_LOGGING_CATEGORY(KAUTH_OSX, "kf5.kauth.apple", QtWarningMsg) namespace KAuth { static AuthorizationRef s_authRef = NULL; AuthorizationRef authRef() { if (!s_authRef) { AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &s_authRef); } return s_authRef; } // GetActionRights return codes: // errAuthorizationSuccess = 0, // errAuthorizationInvalidSet = -60001, /* The authorization rights are invalid. */ // errAuthorizationInvalidRef = -60002, /* The authorization reference is invalid. */ // errAuthorizationInvalidTag = -60003, /* The authorization tag is invalid. */ // errAuthorizationInvalidPointer = -60004, /* The returned authorization is invalid. */ // errAuthorizationDenied = -60005, /* The authorization was denied. */ // errAuthorizationCanceled = -60006, /* The authorization was cancelled by the user. */ // errAuthorizationInteractionNotAllowed = -60007, /* The authorization was denied since no user interaction was possible. */ // errAuthorizationInternal = -60008, /* Unable to obtain authorization for this operation. */ // errAuthorizationExternalizeNotAllowed = -60009, /* The authorization is not allowed to be converted to an external format. */ // errAuthorizationInternalizeNotAllowed = -60010, /* The authorization is not allowed to be created from an external format. */ // errAuthorizationInvalidFlags = -60011, /* The provided option flag(s) are invalid for this authorization operation. */ // errAuthorizationToolExecuteFailure = -60031, /* The specified program could not be executed. */ // errAuthorizationToolEnvironmentError = -60032, /* An invalid status was returned during execution of a privileged tool. */ // errAuthorizationBadAddress = -60033, /* The requested socket address is invalid (must be 0-1023 inclusive). */ static OSStatus GetActionRights(const QString &action, AuthorizationFlags flags, AuthorizationRef auth) { AuthorizationItem item; item.name = action.toUtf8().constData(); item.valueLength = 0; item.value = NULL; item.flags = 0; AuthorizationRights rights; rights.count = 1; rights.items = &item; OSStatus result = AuthorizationCopyRights(auth, &rights, kAuthorizationEmptyEnvironment, flags, NULL); return result; } // On OS X we avoid using a helper but grab privilege from here, the client. AuthServicesBackend::AuthServicesBackend() : AuthBackend() { setCapabilities(AuthorizeFromClientCapability | CheckActionExistenceCapability); } AuthServicesBackend::~AuthServicesBackend() { if (s_authRef) { OSStatus err = AuthorizationFree(s_authRef, kAuthorizationFlagDefaults); qCDebug(KAUTH_OSX) << "AuthorizationFree(" << s_authRef << ") returned" << err; s_authRef = NULL; } } void AuthServicesBackend::setupAction(const QString &) { // Nothing to do here... } Action::AuthStatus AuthServicesBackend::authorizeAction(const QString &action) { Action::AuthStatus retval; OSStatus result = GetActionRights(action, kAuthorizationFlagExtendRights | kAuthorizationFlagInteractionAllowed, authRef()); qCDebug(KAUTH_OSX) << "AuthServicesBackend::authorizeAction(" << action << ") AuthorizationCopyRights returned" << result; switch (result) { case errAuthorizationSuccess: retval = Action::AuthorizedStatus; break; case errAuthorizationCanceled: retval = Action::UserCancelledStatus; break; case errAuthorizationInteractionNotAllowed: case errAuthorizationDenied: retval = Action::DeniedStatus; break; case errAuthorizationInternal: // does this make sense? retval = Action::AuthRequiredStatus; break; case errAuthorizationExternalizeNotAllowed: case errAuthorizationInternalizeNotAllowed: case errAuthorizationToolExecuteFailure: case errAuthorizationToolEnvironmentError: case errAuthorizationBadAddress: retval = Action::ErrorStatus; break; default: retval = Action::InvalidStatus; break; } return retval; } Action::AuthStatus AuthServicesBackend::actionStatus(const QString &action) { Action::AuthStatus retval; OSStatus result = GetActionRights(action, kAuthorizationFlagExtendRights | kAuthorizationFlagPreAuthorize, authRef()); qCDebug(KAUTH_OSX) << "AuthServicesBackend::actionStatus(" << action << ") AuthorizationCopyRights returned" << result; // this function has a simpler return code parser: switch (result) { case errAuthorizationSuccess: retval = Action::AuthorizedStatus; break; case errAuthorizationCanceled: retval = Action::UserCancelledStatus; break; case errAuthorizationInteractionNotAllowed: retval = Action::AuthRequiredStatus; break; default: retval = Action::DeniedStatus; break; } return retval; } QByteArray AuthServicesBackend::callerID() const { AuthorizationExternalForm ext; AuthorizationMakeExternalForm(authRef(), &ext); QByteArray id((const char *)&ext, sizeof(ext)); return id; } -bool AuthServicesBackend::isCallerAuthorized(const QString &action, QByteArray callerID) +bool AuthServicesBackend::isCallerAuthorized(const QString &action, const QByteArray &callerID, const QVariantMap &details) { + Q_UNUSED(details); + AuthorizationExternalForm ext; memcpy(&ext, callerID.data(), sizeof(ext)); AuthorizationRef auth; if (AuthorizationCreateFromExternalForm(&ext, &auth) != noErr) { qCWarning(KAUTH_OSX()) << "AuthorizationCreateFromExternalForm(" << action << "," << callerID.constData() << ") failed"; return false; } OSStatus result = GetActionRights( action, kAuthorizationFlagExtendRights | kAuthorizationFlagInteractionAllowed, auth); AuthorizationFree(auth, kAuthorizationFlagDefaults); qCDebug(KAUTH_OSX) << "AuthServicesBackend::isCallerAuthorized(" << action << "," << callerID.constData() << ") AuthorizationCopyRights returned" << result; return result == errAuthorizationSuccess; } // OS X doesn't distinguish between "action doesn't exist" and "action not allowed". So the // best thing we can do is return true and hope that the action will be created if it didn't exist... bool AuthServicesBackend::actionExists(const QString &) { return true; } }; // namespace KAuth diff --git a/src/backends/mac/AuthServicesBackend.h b/src/backends/mac/AuthServicesBackend.h index 9eb656a..3ddf971 100644 --- a/src/backends/mac/AuthServicesBackend.h +++ b/src/backends/mac/AuthServicesBackend.h @@ -1,50 +1,50 @@ /* * Copyright (C) 2008 Nicola Gigante * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * 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. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . */ #ifndef AUTHSERVICES_BACKEND_H #define AUTHSERVICES_BACKEND_H #include "AuthBackend.h" #include namespace KAuth { class AuthServicesBackend : public AuthBackend { Q_OBJECT Q_PLUGIN_METADATA(IID "org.kde.AuthServicesBackend") Q_INTERFACES(KAuth::AuthBackend) public: AuthServicesBackend(); virtual ~AuthServicesBackend(); virtual void setupAction(const QString &); virtual Action::AuthStatus authorizeAction(const QString &); virtual Action::AuthStatus actionStatus(const QString &); virtual QByteArray callerID() const; - virtual bool isCallerAuthorized(const QString &action, QByteArray callerID); + virtual bool isCallerAuthorized(const QString &action, const QByteArray &callerID, const QVariantMap &details); virtual bool actionExists(const QString &action); }; } // namespace KAuth #endif diff --git a/src/backends/polkit-1/Polkit1Backend.cpp b/src/backends/polkit-1/Polkit1Backend.cpp index 8adb1a8..2c2c34a 100644 --- a/src/backends/polkit-1/Polkit1Backend.cpp +++ b/src/backends/polkit-1/Polkit1Backend.cpp @@ -1,204 +1,229 @@ /* * Copyright (C) 2008 Nicola Gigante * Copyright (C) 2009 Radek Novacek * Copyright (C) 2009-2010 Dario Freddi * Copyright (C) 2020 David Edmundson * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * 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. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . */ #include "Polkit1Backend.h" #include #include #include #include #include #include #include #include #include +#include #include "kauthdebug.h" namespace KAuth { PolkitResultEventLoop::PolkitResultEventLoop(QObject *parent) : QEventLoop(parent) { } PolkitResultEventLoop::~PolkitResultEventLoop() { } void PolkitResultEventLoop::requestQuit(const PolkitQt1::Authority::Result &result) { m_result = result; quit(); } PolkitQt1::Authority::Result PolkitResultEventLoop::result() const { return m_result; } Polkit1Backend::Polkit1Backend() : AuthBackend() { setCapabilities(AuthorizeFromHelperCapability | CheckActionExistenceCapability | PreAuthActionCapability); // Setup useful signals connect(PolkitQt1::Authority::instance(), SIGNAL(configChanged()), this, SLOT(checkForResultChanged())); connect(PolkitQt1::Authority::instance(), SIGNAL(consoleKitDBChanged()), this, SLOT(checkForResultChanged())); } Polkit1Backend::~Polkit1Backend() { } void Polkit1Backend::preAuthAction(const QString &action, QWidget *parent) { // If a parent was not specified, skip this if (!parent) { qCDebug(KAUTH) << "Parent widget does not exist, skipping"; return; } // Are we running our KDE auth agent? if (QDBusConnection::sessionBus().interface()->isServiceRegistered(QLatin1String("org.kde.polkit-kde-authentication-agent-1"))) { // Check if we actually are entitled to use GUI capabilities if (qApp == nullptr || !qobject_cast(qApp)) { qCDebug(KAUTH) << "Not streaming parent as we are on a TTY application"; } // Retrieve the dialog root window Id qulonglong wId = parent->effectiveWinId(); // Send it over the bus to our agent QDBusMessage methodCall = QDBusMessage::createMethodCall(QLatin1String("org.kde.polkit-kde-authentication-agent-1"), QLatin1String("/org/kde/Polkit1AuthAgent"), QLatin1String("org.kde.Polkit1AuthAgent"), QLatin1String("setWIdForAction")); methodCall << action; methodCall << wId; QDBusPendingCall call = QDBusConnection::sessionBus().asyncCall(methodCall); call.waitForFinished(); if (call.isError()) { qCWarning(KAUTH) << "ERROR while streaming the parent!!" << call.error(); } } else { qCDebug(KAUTH) << "KDE polkit agent appears too old or not registered on the bus"; } } Action::AuthStatus Polkit1Backend::authorizeAction(const QString &action) { Q_UNUSED(action) // Always return Yes here, we'll authorize inside isCallerAuthorized return Action::AuthorizedStatus; } void Polkit1Backend::setupAction(const QString &action) { m_cachedResults[action] = actionStatus(action); } Action::AuthStatus Polkit1Backend::actionStatus(const QString &action) { PolkitQt1::SystemBusNameSubject subject(QString::fromUtf8(callerID())); auto authority = PolkitQt1::Authority::instance(); PolkitQt1::Authority::Result r = authority->checkAuthorizationSync(action, subject, PolkitQt1::Authority::None); if (authority->hasError()) { qCDebug(KAUTH) << "Encountered error while checking action status, error code:" << authority->lastError() << authority->errorDetails(); authority->clearError(); return Action::InvalidStatus; } switch (r) { case PolkitQt1::Authority::Yes: return Action::AuthorizedStatus; case PolkitQt1::Authority::No: case PolkitQt1::Authority::Unknown: return Action::DeniedStatus; default: return Action::AuthRequiredStatus; } } QByteArray Polkit1Backend::callerID() const { return QDBusConnection::systemBus().baseService().toUtf8(); } AuthBackend::ExtraCallerIDVerificationMethod Polkit1Backend::extraCallerIDVerificationMethod() const { return VerifyAgainstDBusServiceName; } -bool Polkit1Backend::isCallerAuthorized(const QString &action, QByteArray callerID) +bool Polkit1Backend::isCallerAuthorized(const QString &action, const QByteArray &callerID, const QVariantMap &details) { PolkitQt1::SystemBusNameSubject subject(QString::fromUtf8(callerID)); PolkitQt1::Authority *authority = PolkitQt1::Authority::instance(); - + QMap polkit1Details; + for (auto it = details.cbegin(); it != details.cend(); ++it) { + polkit1Details.insert(it.key(), it.value().toString()); + } PolkitResultEventLoop e; connect(authority, SIGNAL(checkAuthorizationFinished(PolkitQt1::Authority::Result)), &e, SLOT(requestQuit(PolkitQt1::Authority::Result))); +#if POLKITQT1_IS_VERSION(0, 113, 0) + authority->checkAuthorizationWithDetails(action, subject, PolkitQt1::Authority::AllowUserInteraction, polkit1Details); +#else authority->checkAuthorization(action, subject, PolkitQt1::Authority::AllowUserInteraction); +#endif e.exec(); if (authority->hasError()) { qCDebug(KAUTH) << "Encountered error while checking authorization, error code:" << authority->lastError() << authority->errorDetails(); authority->clearError(); } switch (e.result()) { case PolkitQt1::Authority::Yes: return true; default: return false; } } void Polkit1Backend::checkForResultChanged() { for (auto it = m_cachedResults.begin(); it != m_cachedResults.end(); ++it) { const QString action = it.key(); if (it.value() != actionStatus(action)) { *it = actionStatus(action); emit actionStatusChanged(action, *it); } } } bool Polkit1Backend::actionExists(const QString &action) { return m_cachedResults.value(action) != Action::InvalidStatus; } +QVariantMap Polkit1Backend::backendDetails(const DetailsMap &details) +{ + QVariantMap backendDetails; + for (auto it = details.cbegin(); it != details.cend(); ++it) { + switch (it.key()) { + case Action::AuthDetail::DetailMessage: + backendDetails.insert(QStringLiteral("polkit.message"), it.value()); + break; + case Action::AuthDetail::DetailOther: + default: + backendDetails.insert(QStringLiteral("other_details"), it.value()); + break; + } + } + return backendDetails; +} + } // namespace Auth diff --git a/src/backends/polkit-1/Polkit1Backend.h b/src/backends/polkit-1/Polkit1Backend.h index c2bfbe3..0d51e9e 100644 --- a/src/backends/polkit-1/Polkit1Backend.h +++ b/src/backends/polkit-1/Polkit1Backend.h @@ -1,81 +1,82 @@ /* * Copyright (C) 2008 Nicola Gigante * Copyright (C) 2009 Radek Novacek * Copyright (C) 2009-2010 Dario Freddi * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * 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. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . */ #ifndef POLKIT1BACKEND_H #define POLKIT1BACKEND_H #include "AuthBackend.h" #include #include #include #include class QByteArray; namespace KAuth { class Polkit1Backend : public AuthBackend { Q_OBJECT Q_PLUGIN_METADATA(IID "org.kde.Polkit1Backend") Q_INTERFACES(KAuth::AuthBackend) public: Polkit1Backend(); virtual ~Polkit1Backend(); void setupAction(const QString &) override; void preAuthAction(const QString &action, QWidget *parent) override; Action::AuthStatus authorizeAction(const QString &) override; Action::AuthStatus actionStatus(const QString &) override; QByteArray callerID() const override; ExtraCallerIDVerificationMethod extraCallerIDVerificationMethod() const override; - bool isCallerAuthorized(const QString &action, QByteArray callerID) override; + virtual bool isCallerAuthorized(const QString &action, const QByteArray &callerID, const QVariantMap &details) override; bool actionExists(const QString &action) override; + QVariantMap backendDetails(const DetailsMap &details) override; private Q_SLOTS: void checkForResultChanged(); private: QHash m_cachedResults; }; class PolkitResultEventLoop : public QEventLoop { Q_OBJECT public: PolkitResultEventLoop(QObject *parent = nullptr); virtual ~PolkitResultEventLoop(); PolkitQt1::Authority::Result result() const; public Q_SLOTS: void requestQuit(const PolkitQt1::Authority::Result &result); private: PolkitQt1::Authority::Result m_result; }; } // namespace Auth #endif diff --git a/src/kauthaction.cpp b/src/kauthaction.cpp index 654433e..1d37851 100644 --- a/src/kauthaction.cpp +++ b/src/kauthaction.cpp @@ -1,212 +1,232 @@ /* * Copyright (C) 2009-2012 Dario Freddi * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * 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. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . */ #include "kauthaction.h" #include #include class QWidget; #include "kauthexecutejob.h" #include "BackendsManager.h" namespace KAuth { class ActionData : public QSharedData { public: ActionData() : parent(nullptr), timeout(-1) {} ActionData(const ActionData &other) : QSharedData(other) , name(other.name) - , details(other.details) , helperId(other.helperId) + , details(other.details) , args(other.args) , parent(other.parent) , timeout(other.timeout) {} ~ActionData() {} QString name; - QString details; QString helperId; + Action::DetailsMap details; QVariantMap args; QWidget *parent = nullptr; int timeout; }; // Constructors Action::Action() : d(new ActionData()) { } Action::Action(const Action &action) : d(action.d) { } Action::Action(const QString &name) : d(new ActionData()) { setName(name); BackendsManager::authBackend()->setupAction(d->name); } +#ifndef KAUTHCORE_NO_DEPRECATED Action::Action(const QString &name, const QString &details) + : Action(name, DetailsMap{{AuthDetail::DetailOther, details}}) +{ +} +#endif + +Action::Action(const QString &name, const DetailsMap &details) : d(new ActionData()) { setName(name); - setDetails(details); + setDetailsV2(details); BackendsManager::authBackend()->setupAction(d->name); } Action::~Action() { } // Operators Action &Action::operator=(const Action &action) { if (this == &action) { // Protect against self-assignment return *this; } d = action.d; return *this; } bool Action::operator==(const Action &action) const { return d->name == action.d->name; } bool Action::operator!=(const Action &action) const { return d->name != action.d->name; } // Accessors QString Action::name() const { return d->name; } void Action::setName(const QString &name) { d->name = name; } // Accessors int Action::timeout() const { return d->timeout; } void Action::setTimeout(int timeout) { d->timeout = timeout; } +#ifndef KAUTHCORE_NO_DEPRECATED QString Action::details() const { - return d->details; + return d->details.value(AuthDetail::DetailOther).toString(); } void Action::setDetails(const QString &details) +{ + d->details.clear(); + d->details.insert(AuthDetail::DetailOther, details); +} +#endif + +Action::DetailsMap Action::detailsV2() const +{ + return d->details; +} + +void Action::setDetailsV2(const DetailsMap &details) { d->details = details; } bool Action::isValid() const { if (d->name.isEmpty()) { return false; } // Does the backend support checking for known actions? if (BackendsManager::authBackend()->capabilities() & KAuth::AuthBackend::CheckActionExistenceCapability) { // In this case, just ask the backend return BackendsManager::authBackend()->actionExists(name()); } else { // Otherwise, check through a regexp const QRegularExpression re(QRegularExpression::anchoredPattern(QStringLiteral("[0-z]+(\\.[0-z]+)*"))); return re.match(name()).hasMatch(); } } void Action::setArguments(const QVariantMap &arguments) { d->args = arguments; } void Action::addArgument(const QString &key, const QVariant &value) { d->args.insert(key, value); } QVariantMap Action::arguments() const { return d->args; } QString Action::helperId() const { return d->helperId; } // TODO: Check for helper id's syntax void Action::setHelperId(const QString &id) { d->helperId = id; } void Action::setParentWidget(QWidget *parent) { d->parent = parent; } QWidget *Action::parentWidget() const { return d->parent; } Action::AuthStatus Action::status() const { if (!isValid()) { return Action::InvalidStatus; } return BackendsManager::authBackend()->actionStatus(d->name); } ExecuteJob *Action::execute(ExecutionMode mode) { return new ExecuteJob(*this, mode, nullptr); } bool Action::hasHelper() const { return !d->helperId.isEmpty(); } } // namespace Auth diff --git a/src/kauthaction.h b/src/kauthaction.h index b4d143a..b3f0f37 100644 --- a/src/kauthaction.h +++ b/src/kauthaction.h @@ -1,387 +1,443 @@ /* * Copyright (C) 2009-2012 Dario Freddi * Copyright (C) 2008 Nicola Gigante * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * 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. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . */ #ifndef ACTION_H #define ACTION_H #include #include #include #include #include namespace KAuth { class ExecuteJob; class ActionData; /** * @brief Class to access, authorize and execute actions. * * This is the main class of the kauth API. It provides the interface to * manipulate actions. Every action is identified by its name. Every instance * of the Action class with the same name refers to the same action. * * Once you have an action object you can tell the helper to execute it * (asking the user to authenticate if needed) with the execute() method. * The simplest thing to do is to execute a single action synchronously * blocking for the reply by callin exec() on the job object returned by * execute(). * * For asynchronous calls, use KAuth::ExecuteJob::start() instead. * It sends the request * to the helper and returns immediately. Before doing so you should however * connect to at least the KJob::result(KJob *) signal to receive a slot call * once the action is done executing. * * To use the execute() method you have to set the default helper's ID using * the setHelperID() static method. Alternatively, you can specify the helperID using * the overloaded version of the methods that takes it as a parameter. * * Each action object contains a QVariantMap object that is passed directly to the * helper when the action is executed. You can access this map using the arguments() * method. You can insert into it any kind of custom data you need to pass to the helper. * * @code * void MyApp::runAction() * { * action = KAuth::Action("org.kde.myapp.action"); * KAuth::ExecuteJob *job = action.execute(); * connect(job, &KAuth::ExecuteJob::result, this, &MyApp::actionResult); * job->start(); * } * * void MyApp::actionResult(KJob *kjob) * { * auto job = qobject_cast(kjob); * qDebug() << job.error() << job.data(); * } * @endcode * * @since 4.4 */ class KAUTHCORE_EXPORT Action { Q_GADGET public: /** * The three values set by authorization methods */ enum AuthStatus { DeniedStatus, ///< The authorization has been denied by the authorization backend ErrorStatus, ///< An error occurred InvalidStatus, ///< An invalid action cannot be authorized AuthorizedStatus, ///< The authorization has been granted by the authorization backend AuthRequiredStatus, ///< The user could obtain the authorization after authentication UserCancelledStatus ///< The user pressed Cancel the authentication dialog. Currently used only on the mac }; Q_ENUM(AuthStatus) enum ExecutionMode { ExecuteMode, AuthorizeOnlyMode }; Q_ENUM(ExecutionMode) + /** + * The backend specific details. + */ + enum class AuthDetail { + DetailOther = 0, + DetailMessage, ///< The message to show in authentication dialog. + }; + Q_ENUM(AuthDetail) + + typedef QMap DetailsMap; + /** * @brief Default constructor * * This constructor sets the name to the empty string. * Such an action is invalid and cannot be authorized nor executed, so * you need to call setName() before you can use the object. */ Action(); /** Copy constructor */ Action(const Action &action); /** * This creates a new action object with this name * @param name The name of the new action */ Action(const QString &name); /** * This creates a new action object with this name and details * @param name The name of the new action * @param details The details of the action * * @see setDetails + * @deprecated since 5.68 + */ +#ifndef KAUTHCORE_NO_DEPRECATED + KAUTHCORE_DEPRECATED Action(const QString &name, const QString &details); +#endif + + /** + * This creates a new action object with this name and details + * @param name The name of the new action + * @param details The details of the action + * + * @see setDetails + * @since 5.68 */ - Action(const QString &name, const QString &details); + Action(const QString &name, const DetailsMap &details); /// Virtual destructor ~Action(); /// Assignment operator Action &operator=(const Action &action); /** * @brief Comparison operator * * This comparison operator compares the names of two * actions and returns whether they are the same. It does not * care about the arguments stored in the actions. However, * if two actions are invalid they'll match as equal, even * if the invalid names are different. * * @returns true if the two actions are the same or both invalid */ bool operator==(const Action &action) const; /** * @brief Negated comparison operator * * Returns the negation of operator== * * @returns true if the two actions are different and not both invalid */ bool operator!=(const Action &action) const; /** * @brief Gets the action's name. * * This is the unique attribute that identifies * an action object. Two action objects with the same * name always refer to the same action. * * @return The action name */ QString name() const; /** * @brief Sets the action's name. * * It's not common to change the action name * after its creation. Usually you set the name * with the constructor (and you have to, because * there's no default constructor) */ void setName(const QString &name); /** * @brief Gets the action's timeout. * * The timeout of the action in milliseconds * -1 means the default D-Bus timeout (usually 25 seconds) * * @since 5.29 * * @return The action timeouts */ int timeout() const; /** * @brief Sets the action's timeout. * * The timeout of the action in milliseconds * -1 means the default D-Bus timeout (usually 25 seconds) * * @since 5.29 * */ void setTimeout(int timeout); /** * @brief Sets the action's details * * You can use this function to provide the user more details * (if the backend supports it) on the action being authorized in * the authorization dialog + * + * @deprecated since 5.68, use setDetails() with DetailsMap. + */ +#ifndef KAUTHCORE_NO_DEPRECATED + KAUTHCORE_DEPRECATED void setDetails(const QString &details); +#endif + + /** + * @brief Sets the action's details + * + * You can use this function to provide the user more details + * (if the backend supports it) on the action being authorized in + * the authorization dialog + * + * @param details the details describing the action. For e.g, "DetailMessage" key can + * be used to give a customized authentication message. + * + * @since 5.68 + */ + void setDetailsV2(const DetailsMap &details); + + /** + * @brief Gets the action's details + * + * The details that will be shown in the authorization dialog, if the + * backend supports it. + * + * @return The action's details + * @deprecated since 5.68, use detailsV2() with DetailsMap. */ - void setDetails(const QString &details); +#ifndef KAUTHCORE_NO_DEPRECATED + KAUTHCORE_DEPRECATED QString details() const; +#endif /** * @brief Gets the action's details * * The details that will be shown in the authorization dialog, if the * backend supports it. * * @return The action's details + * @since 5.68 */ - QString details() const; + DetailsMap detailsV2() const; /** * @brief Returns if the object represents a valid action * * Action names have to respect a simple syntax. * They have to be all in lowercase characters, separated * by dots. Dots can't appear at the beginning and at the end of * the name. * * In other words, the action name has to match this perl-like * regular expression: * @verbatim * /^[a-z]+(\.[a-z]+)*$/ * @endverbatim * * This method returns false if the action name doesn't match the * valid syntax. * * If the backend supports it, this method also checks if the action is * valid and recognized by the backend itself. * @note This may spawn a nested event loop. * * Invalid actions cannot be authorized nor executed. * The empty string is not a valid action name, so the default * constructor returns an invalid action. */ bool isValid() const; /** * @brief Gets the default helper ID used for actions execution * * The helper ID is the string that uniquely identifies the helper in * the system. It is the string passed to the KAUTH_HELPER() macro * in the helper source. Because one could have different helpers, * you need to specify an helper ID for each execution, or set a default * ID by calling setHelperID(). This method returns the current default * value. * * @return The default helper ID. */ QString helperId() const; /** * @brief Sets the default helper ID used for actions execution * * This method sets the helper ID which contains the body of this action. * If the string is non-empty, the corresponding helper will be fired and * the action executed inside the helper. Otherwise, the action will be just * authorized. * * @note To unset a previously set helper, just pass an empty string * * @param id The default helper ID. * * @see hasHelper * @see helperId */ void setHelperId(const QString &id); /** * @brief Checks if the action has an helper * * This function can be used to check if an helper will be called upon the * execution of an action. Such an helper can be set through setHelperID. If * this function returns false, upon execution the action will be just authorized. * * @since 4.5 * * @return Whether the action has an helper or not * * @see setHelperID */ bool hasHelper() const; /** * @brief Sets the map object used to pass arguments to the helper. * * This method sets the variant map that the application * can use to pass arbitrary data to the helper when executing the action. * * Only non-gui variants are supported. * * @param arguments The new arguments map */ void setArguments(const QVariantMap &arguments); /** * @brief Returns map object used to pass arguments to the helper. * * This method returns the variant map that the application * can use to pass arbitrary data to the helper when executing the action. * * @return The arguments map that will be passed to the helper. */ QVariantMap arguments() const; /** * @brief Convenience method to add an argument. * * This method adds the pair @c key/value to the QVariantMap used to * send custom data to the helper. * * Use this method if you don't want to create a new QVariantMap only to * add a new entry. * * @param key The new entry's key * @param value The value of the new entry */ void addArgument(const QString &key, const QVariant &value); /** * @brief Gets information about the authorization status of an action * * This methods query the authorization backend to know if the user can try * to acquire the authorization for this action. If the result is Action::AuthRequired, * the user can try to acquire the authorization by authenticating. * * It should not be needed to call this method directly, because the execution methods * already take care of all the authorization stuff. * * @return @c Action::Denied if the user doesn't have the authorization to execute the action, * @c Action::Authorized if the action can be executed, * @c Action::AuthRequired if the user could acquire the authorization after authentication, * @c Action::UserCancelled if the user cancels the authentication dialog. Not currently supported by the Polkit backend */ AuthStatus status() const; /** * @brief Get the job object used to execute the action * * @return The KJob::ExecuteJob object to be used to run the action. */ ExecuteJob *execute(ExecutionMode mode = ExecuteMode); /** * @brief Sets a parent widget for the authentication dialog * * This function is used for explicitly setting a parent window for an eventual authentication dialog required when * authorization is triggered. Some backends, in fact, (like polkit-1) need to have a parent explicitly set for displaying * the dialog correctly. * * @note If you are using KAuth through one of KDE's GUI components (KPushButton, KCModule...) you do not need and should not * call this function, as it is already done by the component itself. * * @since 4.6 * * @param parent A QWidget which will be used as the dialog's parent */ void setParentWidget(QWidget *parent); /** * @brief Returns the parent widget for the authentication dialog for this action * * @since 4.6 * * @returns A QWidget which will is being used as the dialog's parent */ QWidget *parentWidget() const; private: QSharedDataPointer d; }; } // namespace Auth #endif diff --git a/src/kauthexecutejob.cpp b/src/kauthexecutejob.cpp index 8d7cd6e..a1d6978 100644 --- a/src/kauthexecutejob.cpp +++ b/src/kauthexecutejob.cpp @@ -1,241 +1,241 @@ /* * Copyright (C) 2009-2012 Dario Freddi * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * 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. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . */ #include "kauthexecutejob.h" #include "BackendsManager.h" #include #include #include #include "kauthdebug.h" namespace KAuth { class Q_DECL_HIDDEN ExecuteJob::Private { public: Private(ExecuteJob *parent) : q(parent) {} ExecuteJob *q; Action action; Action::ExecutionMode mode; QVariantMap data; void doExecuteAction(); void doAuthorizeAction(); void actionPerformedSlot(const QString &action, const ActionReply &reply); void progressStepSlot(const QString &action, int i); void progressStepSlot(const QString &action, const QVariantMap &data); void statusChangedSlot(const QString &action, KAuth::Action::AuthStatus status); }; static QHash s_watchers; ExecuteJob::ExecuteJob(const Action &action, Action::ExecutionMode mode, QObject *parent) : KJob(parent) , d(new Private(this)) { d->action = action; d->mode = mode; HelperProxy *helper = BackendsManager::helperProxy(); connect(helper, SIGNAL(actionPerformed(QString,KAuth::ActionReply)), this, SLOT(actionPerformedSlot(QString,KAuth::ActionReply))); connect(helper, SIGNAL(progressStep(QString,int)), this, SLOT(progressStepSlot(QString,int))); connect(helper, SIGNAL(progressStep(QString,QVariantMap)), this, SLOT(progressStepSlot(QString,QVariantMap))); connect(BackendsManager::authBackend(), SIGNAL(actionStatusChanged(QString,KAuth::Action::AuthStatus)), this, SLOT(statusChangedSlot(QString,KAuth::Action::AuthStatus))); } ExecuteJob::~ExecuteJob() { delete d; } Action ExecuteJob::action() const { return d->action; } QVariantMap ExecuteJob::data() const { return d->data; } void ExecuteJob::start() { if (!d->action.isValid()) { qCWarning(KAUTH) << "Tried to start an invalid action: " << d->action.name(); ActionReply reply(ActionReply::InvalidActionError); reply.setErrorDescription(tr("Tried to start an invalid action")); d->actionPerformedSlot(d->action.name(), reply); return; } switch (d->mode) { case Action::ExecuteMode: QTimer::singleShot(0, this, [this]() {d->doExecuteAction();}); break; case Action::AuthorizeOnlyMode: QTimer::singleShot(0, this, [this]() {d->doAuthorizeAction();}); break; default: { ActionReply reply(ActionReply::InvalidActionError); reply.setErrorDescription(tr("Unknown execution mode chosen")); d->actionPerformedSlot(d->action.name(), reply); } break; } } bool ExecuteJob::kill(KillVerbosity verbosity) { BackendsManager::helperProxy()->stopAction(d->action.name(), d->action.helperId()); KJob::kill(verbosity); return true; } void ExecuteJob::Private::doExecuteAction() { // If this action authorizes from the client, let's do it now if (BackendsManager::authBackend()->capabilities() & KAuth::AuthBackend::AuthorizeFromClientCapability) { if (BackendsManager::authBackend()->capabilities() & KAuth::AuthBackend::PreAuthActionCapability) { BackendsManager::authBackend()->preAuthAction(action.name(), action.parentWidget()); } Action::AuthStatus s = BackendsManager::authBackend()->authorizeAction(action.name()); if (s == Action::AuthorizedStatus) { if (action.hasHelper()) { - BackendsManager::helperProxy()->executeAction(action.name(), action.helperId(), action.arguments(), action.timeout()); + BackendsManager::helperProxy()->executeAction(action.name(), action.helperId(), action.detailsV2(), action.arguments(), action.timeout()); } else { // Done actionPerformedSlot(action.name(), ActionReply::SuccessReply()); } } else { // Abort if authorization fails switch (s) { case Action::DeniedStatus: actionPerformedSlot(action.name(), ActionReply::AuthorizationDeniedReply()); break; case Action::InvalidStatus: actionPerformedSlot(action.name(), ActionReply::InvalidActionReply()); break; case Action::UserCancelledStatus: actionPerformedSlot(action.name(), ActionReply::UserCancelledReply()); break; default: { ActionReply r(ActionReply::BackendError); r.setErrorDescription(tr("Unknown status for the authentication procedure")); actionPerformedSlot(action.name(), r); } break; } } } else if (BackendsManager::authBackend()->capabilities() & KAuth::AuthBackend::AuthorizeFromHelperCapability) { if (BackendsManager::authBackend()->capabilities() & KAuth::AuthBackend::PreAuthActionCapability) { BackendsManager::authBackend()->preAuthAction(action.name(), action.parentWidget()); } if (!action.hasHelper()) { ActionReply r(ActionReply::InvalidActionReply()); r.setErrorDescription(tr("The current backend only allows helper authorization, but this action does not have a helper.")); actionPerformedSlot(action.name(), r); return; } - BackendsManager::helperProxy()->executeAction(action.name(), action.helperId(), action.arguments(), action.timeout()); + BackendsManager::helperProxy()->executeAction(action.name(), action.helperId(), action.detailsV2(), action.arguments(), action.timeout()); } else { // There's something totally wrong here ActionReply r(ActionReply::BackendError); r.setErrorDescription(tr("The backend does not specify how to authorize")); actionPerformedSlot(action.name(), r); } } void ExecuteJob::Private::doAuthorizeAction() { // Check the status first Action::AuthStatus s = action.status(); if (s == Action::AuthRequiredStatus) { // Let's check what to do if (BackendsManager::authBackend()->capabilities() & KAuth::AuthBackend::AuthorizeFromClientCapability) { // In this case we can actually try an authorization if (BackendsManager::authBackend()->capabilities() & KAuth::AuthBackend::PreAuthActionCapability) { BackendsManager::authBackend()->preAuthAction(action.name(), action.parentWidget()); } s = BackendsManager::authBackend()->authorizeAction(action.name()); } else if (BackendsManager::authBackend()->capabilities() & KAuth::AuthBackend::AuthorizeFromHelperCapability) { // In this case, just throw out success, as the auth will take place later s = Action::AuthorizedStatus; } else { // This should never, never happen ActionReply r(ActionReply::BackendError); r.setErrorDescription(tr("The backend does not specify how to authorize")); actionPerformedSlot(action.name(), r); } } // Return based on the current status if (s == Action::AuthorizedStatus) { actionPerformedSlot(action.name(), ActionReply::SuccessReply()); } else { actionPerformedSlot(action.name(), ActionReply::AuthorizationDeniedReply()); } } void ExecuteJob::Private::actionPerformedSlot(const QString &taction, const ActionReply &reply) { if (taction == action.name()) { if (reply.failed()) { q->setError(reply.errorCode()); q->setErrorText(reply.errorDescription()); } else { data = reply.data(); } q->emitResult(); } } void ExecuteJob::Private::progressStepSlot(const QString &taction, int i) { if (taction == action.name()) { q->setPercent(i); } } void ExecuteJob::Private::progressStepSlot(const QString &taction, const QVariantMap &data) { if (taction == action.name()) { emit q->newData(data); } } void ExecuteJob::Private::statusChangedSlot(const QString &taction, Action::AuthStatus status) { if (taction == action.name()) { emit q->statusChanged(status); } } } // namespace Auth #include "moc_kauthexecutejob.cpp"