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

KDECore

  • sources
  • kde-4.12
  • 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 QByteArray DBusHelperProxy::performAction(const QString &action, const QByteArray &callerID, QByteArray arguments)
275 {
276  if (!responder) {
277  return ActionReply::NoResponderReply.serialized();
278  }
279 
280  if (!m_currentAction.isEmpty()) {
281  return ActionReply::HelperBusyReply.serialized();
282  }
283 
284  QVariantMap args;
285  QDataStream s(&arguments, QIODevice::ReadOnly);
286  s >> args;
287 
288  m_currentAction = action;
289  emit remoteSignal(ActionStarted, action, QByteArray());
290  QEventLoop e;
291  e.processEvents(QEventLoop::AllEvents);
292 
293  ActionReply retVal;
294 
295  QTimer *timer = responder->property("__KAuth_Helper_Shutdown_Timer").value<QTimer*>();
296  timer->stop();
297 
298  if (BackendsManager::authBackend()->isCallerAuthorized(action, callerID)) {
299  QString slotname = action;
300  if (slotname.startsWith(m_name + QLatin1Char('.'))) {
301  slotname = slotname.right(slotname.length() - m_name.length() - 1);
302  }
303 
304  slotname.replace(QLatin1Char('.'), QLatin1Char('_'));
305 
306  bool success = QMetaObject::invokeMethod(responder, slotname.toLatin1(), Qt::DirectConnection,
307  Q_RETURN_ARG(ActionReply, retVal), Q_ARG(QVariantMap, args));
308 
309  if (!success) {
310  retVal = ActionReply::NoSuchActionReply;
311  }
312 
313  } else {
314  retVal = ActionReply::AuthorizationDeniedReply;
315  }
316 
317  timer->start();
318 
319  emit remoteSignal(ActionPerformed, action, retVal.serialized());
320  e.processEvents(QEventLoop::AllEvents);
321  m_currentAction.clear();
322  m_stopRequest = false;
323 
324  return retVal.serialized();
325 }
326 
327 
328 uint DBusHelperProxy::authorizeAction(const QString& action, const QByteArray& callerID)
329 {
330  if (!m_currentAction.isEmpty()) {
331  return static_cast<uint>(Action::Error);
332  }
333 
334  m_currentAction = action;
335 
336  uint retVal;
337 
338  QTimer *timer = responder->property("__KAuth_Helper_Shutdown_Timer").value<QTimer*>();
339  timer->stop();
340 
341  if (BackendsManager::authBackend()->isCallerAuthorized(action, callerID)) {
342  retVal = static_cast<uint>(Action::Authorized);
343  } else {
344  retVal = static_cast<uint>(Action::Denied);
345  }
346 
347  timer->start();
348  m_currentAction.clear();
349 
350  return retVal;
351 }
352 
353 
354 void DBusHelperProxy::sendDebugMessage(int level, const char *msg)
355 {
356  QByteArray blob;
357  QDataStream stream(&blob, QIODevice::WriteOnly);
358 
359  stream << level << QString::fromLocal8Bit(msg);
360 
361  emit remoteSignal(DebugMessage, m_currentAction, blob);
362 }
363 
364 void DBusHelperProxy::sendProgressStep(int step)
365 {
366  QByteArray blob;
367  QDataStream stream(&blob, QIODevice::WriteOnly);
368 
369  stream << step;
370 
371  emit remoteSignal(ProgressStepIndicator, m_currentAction, blob);
372 }
373 
374 void DBusHelperProxy::sendProgressStep(const QVariantMap &data)
375 {
376  QByteArray blob;
377  QDataStream stream(&blob, QIODevice::WriteOnly);
378 
379  stream << data;
380 
381  emit remoteSignal(ProgressStepData, m_currentAction, blob);
382 }
383 
384 void debugMessageReceived(int t, const QString &message)
385 {
386  QtMsgType type = (QtMsgType)t;
387  switch (type) {
388  case QtDebugMsg:
389  qDebug("Debug message from helper: %s", message.toLatin1().data());
390  break;
391  case QtWarningMsg:
392  qWarning("Warning from helper: %s", message.toLatin1().data());
393  break;
394  case QtCriticalMsg:
395  qCritical("Critical warning from helper: %s", message.toLatin1().data());
396  break;
397  case QtFatalMsg:
398  qFatal("Fatal error from helper: %s", message.toLatin1().data());
399  break;
400  }
401 }
402 
403 } // namespace Auth
404 
405 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
QString
QObject
KAuth::ActionReply::setErrorDescription
void setErrorDescription(const QString &error)
Sets a human-readble description of the error.
Definition: kauthactionreply.cpp:134
KMessage::Error
Error message.
Definition: kmessage.h:57
KAuth::Action::AuthStatus
AuthStatus
The three values returned by authorization methods.
Definition: kauthaction.h:78
KAuth::debugMessageReceived
static void debugMessageReceived(int t, const QString &message)
Definition: DBusHelperProxy.cpp:384
KAuth::ActionReply::serialized
QByteArray serialized() const
Serialize the reply into a QByteArray.
Definition: kauthactionreply.cpp:139
KAuth::DBusHelperProxy
Definition: DBusHelperProxy.h:31
klocalizedstring.h
KAuth::ActionReply
Class that encapsulates a reply coming from the helper after executing an action. ...
Definition: kauthactionreply.h:370
QPair
KAuth::HelperSupport::progressStep
void progressStep(int step)
Send a progressStep signal to the caller application.
Definition: kauthhelpersupport.cpp:122
DBusHelperProxy.h
BackendsManager.h
QList< QVariant >
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:47:07 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
  • kjsembed
  •   WTF
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Nepomuk-Core
  • 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