• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.14.38 API Reference
  • KDE Home
  • Contact Us
 

KDECore

  • kdecore
  • auth
  • backends
  • dbus
DBusHelperProxy.cpp
Go to the documentation of this file.
1/*
2* Copyright (C) 2008 Nicola Gigante <nicola.gigante@gmail.com>
3* Copyright (C) 2009-2010 Dario Freddi <drf@kde.org>
4*
5* This program is free software; you can redistribute it and/or modify
6* it under the terms of the GNU Lesser General Public License as published by
7* the Free Software Foundation; either version 2.1 of the License, or
8* (at your option) any later version.
9*
10* This program is distributed in the hope that it will be useful,
11* but WITHOUT ANY WARRANTY; without even the implied warranty of
12* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13* GNU General Public License for more details.
14*
15* You should have received a copy of the GNU Lesser General Public License
16* along with this program; if not, write to the
17* Free Software Foundation, Inc.,
18* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA .
19*/
20
21#include "DBusHelperProxy.h"
22
23#include <QtCore/qplugin.h>
24#include <QObject>
25#include <QMap>
26#include <QtDBus/QDBusMessage>
27#include <QtDBus/QDBusConnection>
28#include <QDebug>
29#include <QTimer>
30
31#include <klocalizedstring.h>
32
33#include <syslog.h>
34
35#include "BackendsManager.h"
36#include "authadaptor.h"
37
38Q_DECLARE_METATYPE(QTimer*)
39
40namespace KAuth
41{
42
43static void debugMessageReceived(int t, const QString &message);
44
45void DBusHelperProxy::stopAction(const QString &action, const QString &helperID)
46{
47 QDBusMessage message;
48 message = QDBusMessage::createMethodCall(helperID, QLatin1String("/"), QLatin1String("org.kde.auth"), QLatin1String("stopAction"));
49
50 QList<QVariant> args;
51 args << action;
52 message.setArguments(args);
53
54 QDBusConnection::systemBus().asyncCall(message);
55}
56
57bool DBusHelperProxy::executeActions(const QList<QPair<QString, QVariantMap> > &list, const QString &helperID)
58{
59 QByteArray blob;
60 QDataStream stream(&blob, QIODevice::WriteOnly);
61
62 stream << list;
63
64 QDBusConnection::systemBus().interface()->startService(helperID);
65
66 if (!QDBusConnection::systemBus().connect(helperID, QLatin1String("/"), QLatin1String("org.kde.auth"), QLatin1String("remoteSignal"), this, SLOT(remoteSignalReceived(int,QString,QByteArray)))) {
67 return false;
68 }
69
70 QDBusMessage message;
71 message = QDBusMessage::createMethodCall(helperID, QLatin1String("/"), QLatin1String("org.kde.auth"), QLatin1String("performActions"));
72
73 QList<QVariant> args;
74 args << blob << BackendsManager::authBackend()->callerID();
75 message.setArguments(args);
76
77 QDBusPendingCall reply = QDBusConnection::systemBus().asyncCall(message); // This is a NO_REPLY method
78 if (reply.reply().type() == QDBusMessage::ErrorMessage) {
79 return false;
80 }
81
82 return true;
83}
84
85ActionReply DBusHelperProxy::executeAction(const QString &action, const QString &helperID, const QVariantMap &arguments)
86{
87 if (!m_actionsInProgress.isEmpty()) {
88 return ActionReply::HelperBusyReply;
89 }
90
91 QByteArray blob;
92 QDataStream stream(&blob, QIODevice::WriteOnly);
93
94 stream << arguments;
95
96 QDBusConnection::systemBus().interface()->startService(helperID);
97
98 if (!QDBusConnection::systemBus().connect(helperID, QLatin1String("/"), QLatin1String("org.kde.auth"), QLatin1String("remoteSignal"), this, SLOT(remoteSignalReceived(int,QString,QByteArray)))) {
99 ActionReply errorReply = ActionReply::DBusErrorReply;
100 errorReply.setErrorDescription(i18n("DBus Backend error: connection to helper failed. %1",
101 QDBusConnection::systemBus().lastError().message()));
102 return errorReply;
103 }
104
105 QDBusMessage message;
106 message = QDBusMessage::createMethodCall(helperID, QLatin1String("/"), QLatin1String("org.kde.auth"), QLatin1String("performAction"));
107
108 QList<QVariant> args;
109 args << action << BackendsManager::authBackend()->callerID() << blob;
110 message.setArguments(args);
111
112 m_actionsInProgress.push_back(action);
113
114 QEventLoop e;
115 QDBusPendingCall pendingCall = QDBusConnection::systemBus().asyncCall(message);
116 QDBusPendingCallWatcher watcher(pendingCall, this);
117 connect(&watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), &e, SLOT(quit()));
118 e.exec();
119
120 QDBusMessage reply = pendingCall.reply();
121
122 if (reply.type() == QDBusMessage::ErrorMessage) {
123 ActionReply r = ActionReply::DBusErrorReply;
124 r.setErrorDescription(i18n("DBus Backend error: could not contact the helper. "
125 "Connection error: %1. Message error: %2", QDBusConnection::systemBus().lastError().message(),
126 reply.errorMessage()));
127 qDebug() << reply.errorMessage();
128
129 // The remote signal will never arrive: so let's erase the action from the list ourselves
130 m_actionsInProgress.removeOne(action);
131
132 return r;
133 }
134
135 if (reply.arguments().size() != 1) {
136 ActionReply errorReply = ActionReply::DBusErrorReply;
137 errorReply.setErrorDescription(i18n("DBus Backend error: received corrupt data from helper %1 %2",
138 reply.arguments().size(), QDBusConnection::systemBus().lastError().message()));
139
140 // The remote signal may never arrive: so let's erase the action from the list ourselves
141 m_actionsInProgress.removeOne(action);
142
143 return errorReply;
144 }
145
146 return ActionReply::deserialize(reply.arguments().first().toByteArray());
147}
148
149Action::AuthStatus DBusHelperProxy::authorizeAction(const QString& action, const QString& helperID)
150{
151 if (!m_actionsInProgress.isEmpty()) {
152 return Action::Error;
153 }
154
155 QDBusConnection::systemBus().interface()->startService(helperID);
156
157 QDBusMessage message;
158 message = QDBusMessage::createMethodCall(helperID, QLatin1String("/"), QLatin1String("org.kde.auth"), QLatin1String("authorizeAction"));
159
160 QList<QVariant> args;
161 args << action << BackendsManager::authBackend()->callerID();
162 message.setArguments(args);
163
164 m_actionsInProgress.push_back(action);
165
166 QEventLoop e;
167 QDBusPendingCall pendingCall = QDBusConnection::systemBus().asyncCall(message);
168 QDBusPendingCallWatcher watcher(pendingCall, this);
169 connect(&watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), &e, SLOT(quit()));
170 e.exec();
171
172 m_actionsInProgress.removeOne(action);
173
174 QDBusMessage reply = pendingCall.reply();
175
176 if (reply.type() == QDBusMessage::ErrorMessage || reply.arguments().size() != 1) {
177 return Action::Error;
178 }
179
180 return static_cast<Action::AuthStatus>(reply.arguments().first().toUInt());
181}
182
183bool DBusHelperProxy::initHelper(const QString &name)
184{
185 new AuthAdaptor(this);
186
187 if (!QDBusConnection::systemBus().registerService(name)) {
188 return false;
189 }
190
191 if (!QDBusConnection::systemBus().registerObject(QLatin1String("/"), this)) {
192 return false;
193 }
194
195 m_name = name;
196
197 return true;
198}
199
200void DBusHelperProxy::setHelperResponder(QObject *o)
201{
202 responder = o;
203}
204
205void DBusHelperProxy::remoteSignalReceived(int t, const QString &action, QByteArray blob)
206{
207 SignalType type = (SignalType)t;
208 QDataStream stream(&blob, QIODevice::ReadOnly);
209
210 if (type == ActionStarted) {
211 emit actionStarted(action);
212 } else if (type == ActionPerformed) {
213 ActionReply reply = ActionReply::deserialize(blob);
214
215 m_actionsInProgress.removeOne(action);
216 emit actionPerformed(action, reply);
217 } else if (type == DebugMessage) {
218 int level;
219 QString message;
220
221 stream >> level >> message;
222
223 debugMessageReceived(level, message);
224 } else if (type == ProgressStepIndicator) {
225 int step;
226 stream >> step;
227
228 emit progressStep(action, step);
229 } else if (type == ProgressStepData) {
230 QVariantMap data;
231 stream >> data;
232
233 emit progressStep(action, data);
234 }
235}
236
237void DBusHelperProxy::stopAction(const QString &action)
238{
239 Q_UNUSED(action)
240#ifdef __GNUC__
241#warning FIXME: The stop request should be action-specific rather than global
242#endif
243 m_stopRequest = true;
244}
245
246bool DBusHelperProxy::hasToStopAction()
247{
248 QEventLoop loop;
249 loop.processEvents(QEventLoop::AllEvents);
250
251 return m_stopRequest;
252}
253
254void DBusHelperProxy::performActions(QByteArray blob, const QByteArray &callerID)
255{
256 QDataStream stream(&blob, QIODevice::ReadOnly);
257 QList< QPair< QString, QVariantMap > > actions;
258
259 stream >> actions;
260
261 QList< QPair< QString, QVariantMap > >::const_iterator i = actions.constBegin();
262 while (i != actions.constEnd()) {
263 QByteArray blob;
264 QDataStream stream(&blob, QIODevice::WriteOnly);
265
266 stream << i->second;
267
268 performAction(i->first, callerID, blob);
269
270 ++i;
271 }
272}
273
274bool DBusHelperProxy::isCallerAuthorized(const QString &action, const QByteArray &callerID)
275{
276 // Check the caller is really who it says it is
277 switch (BackendsManager::authBackend()->extraCallerIDVerificationMethod()) {
278 case AuthBackend::NoExtraCallerIDVerificationMethod:
279 break;
280
281 case AuthBackend::VerifyAgainstDBusServiceName:
282 if (message().service().toUtf8() != callerID) {
283 return false;
284 }
285 break;
286
287 case AuthBackend::VerifyAgainstDBusServicePid:
288 if (connection().interface()->servicePid(message().service()).value() != callerID.toUInt()) {
289 return false;
290 }
291 break;
292 }
293
294 return BackendsManager::authBackend()->isCallerAuthorized(action, callerID);
295}
296
297QByteArray DBusHelperProxy::performAction(const QString &action, const QByteArray &callerID, QByteArray arguments)
298{
299 if (!responder) {
300 return ActionReply::NoResponderReply.serialized();
301 }
302
303 if (!m_currentAction.isEmpty()) {
304 return ActionReply::HelperBusyReply.serialized();
305 }
306
307 QVariantMap args;
308 QDataStream s(&arguments, QIODevice::ReadOnly);
309 s >> args;
310
311 m_currentAction = action;
312 emit remoteSignal(ActionStarted, action, QByteArray());
313 QEventLoop e;
314 e.processEvents(QEventLoop::AllEvents);
315
316 ActionReply retVal;
317
318 QTimer *timer = responder->property("__KAuth_Helper_Shutdown_Timer").value<QTimer*>();
319 timer->stop();
320
321 if (isCallerAuthorized(action, callerID)) {
322 QString slotname = action;
323 if (slotname.startsWith(m_name + QLatin1Char('.'))) {
324 slotname = slotname.right(slotname.length() - m_name.length() - 1);
325 }
326
327 slotname.replace(QLatin1Char('.'), QLatin1Char('_'));
328
329 bool success = QMetaObject::invokeMethod(responder, slotname.toLatin1(), Qt::DirectConnection,
330 Q_RETURN_ARG(ActionReply, retVal), Q_ARG(QVariantMap, args));
331
332 if (!success) {
333 retVal = ActionReply::NoSuchActionReply;
334 }
335
336 } else {
337 retVal = ActionReply::AuthorizationDeniedReply;
338 }
339
340 timer->start();
341
342 emit remoteSignal(ActionPerformed, action, retVal.serialized());
343 e.processEvents(QEventLoop::AllEvents);
344 m_currentAction.clear();
345 m_stopRequest = false;
346
347 return retVal.serialized();
348}
349
350
351uint DBusHelperProxy::authorizeAction(const QString& action, const QByteArray& callerID)
352{
353 if (!m_currentAction.isEmpty()) {
354 return static_cast<uint>(Action::Error);
355 }
356
357 m_currentAction = action;
358
359 uint retVal;
360
361 QTimer *timer = responder->property("__KAuth_Helper_Shutdown_Timer").value<QTimer*>();
362 timer->stop();
363
364 if (isCallerAuthorized(action, callerID)) {
365 retVal = static_cast<uint>(Action::Authorized);
366 } else {
367 retVal = static_cast<uint>(Action::Denied);
368 }
369
370 timer->start();
371 m_currentAction.clear();
372
373 return retVal;
374}
375
376
377void DBusHelperProxy::sendDebugMessage(int level, const char *msg)
378{
379 QByteArray blob;
380 QDataStream stream(&blob, QIODevice::WriteOnly);
381
382 stream << level << QString::fromLocal8Bit(msg);
383
384 emit remoteSignal(DebugMessage, m_currentAction, blob);
385}
386
387void DBusHelperProxy::sendProgressStep(int step)
388{
389 QByteArray blob;
390 QDataStream stream(&blob, QIODevice::WriteOnly);
391
392 stream << step;
393
394 emit remoteSignal(ProgressStepIndicator, m_currentAction, blob);
395}
396
397void DBusHelperProxy::sendProgressStep(const QVariantMap &data)
398{
399 QByteArray blob;
400 QDataStream stream(&blob, QIODevice::WriteOnly);
401
402 stream << data;
403
404 emit remoteSignal(ProgressStepData, m_currentAction, blob);
405}
406
407void debugMessageReceived(int t, const QString &message)
408{
409 QtMsgType type = (QtMsgType)t;
410 switch (type) {
411 case QtDebugMsg:
412 qDebug("Debug message from helper: %s", message.toLatin1().data());
413 break;
414 case QtWarningMsg:
415 qWarning("Warning from helper: %s", message.toLatin1().data());
416 break;
417 case QtCriticalMsg:
418 qCritical("Critical warning from helper: %s", message.toLatin1().data());
419 break;
420 case QtFatalMsg:
421 qFatal("Fatal error from helper: %s", message.toLatin1().data());
422 break;
423 }
424}
425
426} // namespace Auth
427
428Q_EXPORT_PLUGIN2(kauth_helper_backend, KAuth::DBusHelperProxy)
BackendsManager.h
DBusHelperProxy.h
KAuth::ActionReply
Class that encapsulates a reply coming from the helper after executing an action.
Definition: kauthactionreply.h:371
KAuth::ActionReply::DBusErrorReply
static const ActionReply DBusErrorReply
errorCode() == DBusError
Definition: kauthactionreply.h:394
KAuth::ActionReply::AuthorizationDeniedReply
static const ActionReply AuthorizationDeniedReply
errorCode() == AuthorizationDenied
Definition: kauthactionreply.h:391
KAuth::ActionReply::setErrorDescription
void setErrorDescription(const QString &error)
Sets a human-readble description of the error.
Definition: kauthactionreply.cpp:134
KAuth::ActionReply::deserialize
static ActionReply deserialize(const QByteArray &data)
Deserialize a reply from a QByteArray.
Definition: kauthactionreply.cpp:149
KAuth::ActionReply::HelperBusyReply
static const ActionReply HelperBusyReply
errorCode() == HelperBusy
Definition: kauthactionreply.h:393
KAuth::ActionReply::serialized
QByteArray serialized() const
Serialize the reply into a QByteArray.
Definition: kauthactionreply.cpp:139
KAuth::ActionReply::NoResponderReply
static const ActionReply NoResponderReply
errorCode() == NoResponder
Definition: kauthactionreply.h:388
KAuth::ActionReply::NoSuchActionReply
static const ActionReply NoSuchActionReply
errorCode() == NoSuchAction
Definition: kauthactionreply.h:389
KAuth::Action::AuthStatus
AuthStatus
The three values returned by authorization methods.
Definition: kauthaction.h:78
KAuth::Action::Error
@ Error
An error occurred.
Definition: kauthaction.h:80
KAuth::Action::Denied
@ Denied
The authorization has been denied by the authorization backend.
Definition: kauthaction.h:79
KAuth::Action::Authorized
@ Authorized
The authorization has been granted by the authorization backend.
Definition: kauthaction.h:82
KAuth::AuthBackend::VerifyAgainstDBusServiceName
@ VerifyAgainstDBusServiceName
Definition: AuthBackend.h:48
KAuth::AuthBackend::VerifyAgainstDBusServicePid
@ VerifyAgainstDBusServicePid
Definition: AuthBackend.h:49
KAuth::AuthBackend::NoExtraCallerIDVerificationMethod
@ NoExtraCallerIDVerificationMethod
Definition: AuthBackend.h:47
KAuth::AuthBackend::callerID
virtual QByteArray callerID() const =0
KAuth::AuthBackend::isCallerAuthorized
virtual bool isCallerAuthorized(const QString &action, QByteArray callerID)=0
KAuth::BackendsManager::authBackend
static AuthBackend * authBackend()
Definition: BackendsManager.cpp:120
KAuth::DBusHelperProxy
Definition: DBusHelperProxy.h:33
KAuth::DBusHelperProxy::executeActions
virtual bool executeActions(const QList< QPair< QString, QVariantMap > > &list, const QString &helperID)
Definition: DBusHelperProxy.cpp:57
KAuth::DBusHelperProxy::performAction
QByteArray performAction(const QString &action, const QByteArray &callerID, QByteArray arguments)
Definition: DBusHelperProxy.cpp:297
KAuth::DBusHelperProxy::sendProgressStep
virtual void sendProgressStep(int step)
Definition: DBusHelperProxy.cpp:387
KAuth::DBusHelperProxy::performActions
void performActions(QByteArray blob, const QByteArray &callerID)
Definition: DBusHelperProxy.cpp:254
KAuth::DBusHelperProxy::sendDebugMessage
virtual void sendDebugMessage(int level, const char *msg)
Definition: DBusHelperProxy.cpp:377
KAuth::DBusHelperProxy::authorizeAction
uint authorizeAction(const QString &action, const QByteArray &callerID)
Definition: DBusHelperProxy.cpp:351
KAuth::DBusHelperProxy::executeAction
virtual ActionReply executeAction(const QString &action, const QString &helperID, const QVariantMap &arguments)
Definition: DBusHelperProxy.cpp:85
KAuth::DBusHelperProxy::initHelper
virtual bool initHelper(const QString &name)
Definition: DBusHelperProxy.cpp:183
KAuth::DBusHelperProxy::hasToStopAction
virtual bool hasToStopAction()
Definition: DBusHelperProxy.cpp:246
KAuth::DBusHelperProxy::setHelperResponder
virtual void setHelperResponder(QObject *o)
Definition: DBusHelperProxy.cpp:200
KAuth::DBusHelperProxy::remoteSignal
void remoteSignal(int type, const QString &action, const QByteArray &blob)
KAuth::DBusHelperProxy::stopAction
void stopAction(const QString &action)
Definition: DBusHelperProxy.cpp:237
KAuth::HelperProxy::progressStep
void progressStep(const QString &action, int progress)
KAuth::HelperProxy::actionPerformed
void actionPerformed(const QString &action, ActionReply reply)
KAuth::HelperProxy::actionStarted
void actionStarted(const QString &action)
QList
Definition: kaboutdata.h:33
QObject
QPair
QString
klocalizedstring.h
i18n
QString i18n(const char *text)
Returns a localized version of a string.
Definition: klocalizedstring.h:630
KAuth
Definition: AuthBackend.cpp:24
KAuth::debugMessageReceived
static void debugMessageReceived(int t, const QString &message)
Definition: DBusHelperProxy.cpp:407
KMessage::message
void message(KMessage::MessageType messageType, const QString &text, const QString &caption=QString())
Display a long message of a certain type.
Definition: kmessage.cpp:92
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Feb 20 2023 00:00:00 by doxygen 1.9.6 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KDECore

Skip menu "KDECore"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Modules
  • Related Pages

kdelibs-4.14.38 API Reference

Skip menu "kdelibs-4.14.38 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal