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

KDECore

  • sources
  • kde-4.14
  • kdelibs
  • 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 
38 Q_DECLARE_METATYPE(QTimer*)
39 
40 namespace KAuth
41 {
42 
43 static void debugMessageReceived(int t, const QString &message);
44 
45 void 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 
57 bool 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 
85 ActionReply 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 
149 Action::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 
183 bool 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 
200 void DBusHelperProxy::setHelperResponder(QObject *o)
201 {
202  responder = o;
203 }
204 
205 void 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 
237 void 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 
246 bool DBusHelperProxy::hasToStopAction()
247 {
248  QEventLoop loop;
249  loop.processEvents(QEventLoop::AllEvents);
250 
251  return m_stopRequest;
252 }
253 
254 void 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 
274 bool 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 
297 QByteArray 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 
351 uint 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 
377 void 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 
387 void 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 
397 void 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 
407 void 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 
428 Q_EXPORT_PLUGIN2(kauth_helper_backend, KAuth::DBusHelperProxy)
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
i18n
QString i18n(const char *text)
Returns a localized version of a string.
Definition: klocalizedstring.h:630
QVariant::toByteArray
QByteArray toByteArray() const
QDBusMessage::errorMessage
QString errorMessage() const
QDBusConnectionInterface::startService
QDBusReply< void > startService(const QString &name)
QByteArray::toUInt
uint toUInt(bool *ok, int base) const
QEventLoop
QByteArray
QDataStream
QDBusConnection::interface
QDBusConnectionInterface * interface() const
QDBusPendingCallWatcher
QDBusMessage::arguments
QList< QVariant > arguments() const
QDBusError::message
QString message() const
QVariant::value
T value() const
QDBusMessage::type
MessageType type() const
QDBusConnection::systemBus
QDBusConnection systemBus()
QList::size
int size() const
QString::fromLocal8Bit
QString fromLocal8Bit(const char *str, int size)
QVariant::toUInt
uint toUInt(bool *ok) const
QObject::property
QVariant property(const char *name) const
QTimer
QEventLoop::exec
int exec(QFlags< QEventLoop::ProcessEventsFlag > flags)
QObject
KAuth::ActionReply::setErrorDescription
void setErrorDescription(const QString &error)
Sets a human-readble description of the error.
Definition: kauthactionreply.cpp:134
QDBusPendingCall
QString::startsWith
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const
KMessage::Error
Error message.
Definition: kmessage.h:57
QList::first
T & first()
QString
QList< QVariant >
QPair
QString::right
QString right(int n) const
KAuth::Action::AuthStatus
AuthStatus
The three values returned by authorization methods.
Definition: kauthaction.h:78
QLatin1Char
QTimer::stop
void stop()
QMetaObject::invokeMethod
bool invokeMethod(QObject *obj, const char *member, Qt::ConnectionType type, QGenericReturnArgument ret, QGenericArgument val0, QGenericArgument val1, QGenericArgument val2, QGenericArgument val3, QGenericArgument val4, QGenericArgument val5, QGenericArgument val6, QGenericArgument val7, QGenericArgument val8, QGenericArgument val9)
QString::replace
QString & replace(int position, int n, QChar after)
KAuth::debugMessageReceived
static void debugMessageReceived(int t, const QString &message)
Definition: DBusHelperProxy.cpp:407
KAuth::ActionReply::serialized
QByteArray serialized() const
Serialize the reply into a QByteArray.
Definition: kauthactionreply.cpp:139
KAuth::DBusHelperProxy
Definition: DBusHelperProxy.h:32
QString::toLatin1
QByteArray toLatin1() const
QDBusMessage
QLatin1String
klocalizedstring.h
QEventLoop::processEvents
bool processEvents(QFlags< QEventLoop::ProcessEventsFlag > flags)
QString::length
int length() const
QByteArray::data
char * data()
KAuth::ActionReply
Class that encapsulates a reply coming from the helper after executing an action. ...
Definition: kauthactionreply.h:370
QDBusConnection::asyncCall
QDBusPendingCall asyncCall(const QDBusMessage &message, int timeout) const
QDBusMessage::setArguments
void setArguments(const QList< QVariant > &arguments)
QTimer::start
void start(int msec)
QDBusConnection::lastError
QDBusError lastError() const
KAuth::HelperSupport::progressStep
void progressStep(int step)
Send a progressStep signal to the caller application.
Definition: kauthhelpersupport.cpp:122
QList::constBegin
const_iterator constBegin() const
DBusHelperProxy.h
BackendsManager.h
QDBusMessage::createMethodCall
QDBusMessage createMethodCall(const QString &service, const QString &path, const QString &interface, const QString &method)
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:22:10 by doxygen 1.8.7 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 API Reference

Skip menu "kdelibs 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

Search



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