00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "DBusHelperProxy.h"
00022
00023 #include <QObject>
00024 #include <QMap>
00025 #include <QtDBus/QDBusMessage>
00026 #include <QtDBus/QDBusConnection>
00027 #include <QDebug>
00028 #include <QTimer>
00029
00030 #include <klocalizedstring.h>
00031
00032 #include <syslog.h>
00033
00034 #include "BackendsManager.h"
00035 #include "authadaptor.h"
00036
00037 #ifndef KDE_USE_FINAL
00038 Q_DECLARE_METATYPE(QTimer*)
00039 #endif
00040
00041 namespace KAuth
00042 {
00043
00044 static void debugMessageReceived(int t, const QString &message);
00045
00046 void DBusHelperProxy::stopAction(const QString &action, const QString &helperID)
00047 {
00048 QDBusMessage message;
00049 message = QDBusMessage::createMethodCall(helperID, "/", "org.kde.auth", "stopAction");
00050
00051 QList<QVariant> args;
00052 args << action;
00053 message.setArguments(args);
00054
00055 QDBusConnection::systemBus().asyncCall(message);
00056 }
00057
00058 bool DBusHelperProxy::executeActions(const QList<QPair<QString, QVariantMap> > &list, const QString &helperID)
00059 {
00060 QByteArray blob;
00061 QDataStream stream(&blob, QIODevice::WriteOnly);
00062
00063 stream << list;
00064
00065 QDBusConnection::systemBus().interface()->startService(helperID);
00066
00067 if (!QDBusConnection::systemBus().connect(helperID, "/", "org.kde.auth", "remoteSignal", this, SLOT(remoteSignalReceived(int, const QString &, QByteArray)))) {
00068 return false;
00069 }
00070
00071 QDBusMessage message;
00072 message = QDBusMessage::createMethodCall(helperID, "/", "org.kde.auth", "performActions");
00073
00074 QList<QVariant> args;
00075 args << blob << BackendsManager::authBackend()->callerID();
00076 message.setArguments(args);
00077
00078 QDBusPendingCall reply = QDBusConnection::systemBus().asyncCall(message);
00079 if (reply.reply().type() == QDBusMessage::ErrorMessage) {
00080 return false;
00081 }
00082
00083 return true;
00084 }
00085
00086 ActionReply DBusHelperProxy::executeAction(const QString &action, const QString &helperID, const QVariantMap &arguments)
00087 {
00088 if (!m_actionsInProgress.isEmpty()) {
00089 return ActionReply::HelperBusyReply;
00090 }
00091
00092 QByteArray blob;
00093 QDataStream stream(&blob, QIODevice::WriteOnly);
00094
00095 stream << arguments;
00096
00097 QDBusConnection::systemBus().interface()->startService(helperID);
00098
00099 if (!QDBusConnection::systemBus().connect(helperID, "/", "org.kde.auth", "remoteSignal", this, SLOT(remoteSignalReceived(int, const QString &, QByteArray)))) {
00100 ActionReply errorReply = ActionReply::DBusErrorReply;
00101 errorReply.setErrorDescription(i18n("DBus Backend error: connection to helper failed. %1",
00102 QDBusConnection::systemBus().lastError().message()));
00103 return errorReply;
00104 }
00105
00106 QDBusMessage message;
00107 message = QDBusMessage::createMethodCall(helperID, "/", "org.kde.auth", "performAction");
00108
00109 QList<QVariant> args;
00110 args << action << BackendsManager::authBackend()->callerID() << blob;
00111 message.setArguments(args);
00112
00113 m_actionsInProgress.push_back(action);
00114
00115 QEventLoop e;
00116 QDBusPendingCall pendingCall = QDBusConnection::systemBus().asyncCall(message);
00117 QDBusPendingCallWatcher watcher(pendingCall, this);
00118 connect(&watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), &e, SLOT(quit()));
00119 e.exec();
00120
00121 QDBusMessage reply = pendingCall.reply();
00122
00123 if (reply.type() == QDBusMessage::ErrorMessage) {
00124 ActionReply r = ActionReply::DBusErrorReply;
00125 r.setErrorDescription(i18n("DBus Backend error: could not contact the helper. "
00126 "Connection error: %1. Message error: %2", QDBusConnection::systemBus().lastError().message(),
00127 reply.errorMessage()));
00128 qDebug() << reply.errorMessage();
00129
00130 return r;
00131 }
00132
00133 if (reply.arguments().size() != 1) {
00134 ActionReply errorReply = ActionReply::DBusErrorReply;
00135 errorReply.setErrorDescription(i18n("DBus Backend error: received corrupt data from helper %1 %2",
00136 reply.arguments().size(), QDBusConnection::systemBus().lastError().message()));
00137 return errorReply;
00138 }
00139
00140 return ActionReply::deserialize(reply.arguments().first().toByteArray());
00141 }
00142
00143 bool DBusHelperProxy::initHelper(const QString &name)
00144 {
00145 new AuthAdaptor(this);
00146
00147 if (!QDBusConnection::systemBus().registerService(name)) {
00148 return false;
00149 }
00150
00151 if (!QDBusConnection::systemBus().registerObject("/", this)) {
00152 return false;
00153 }
00154
00155 m_name = name;
00156
00157 return true;
00158 }
00159
00160 void DBusHelperProxy::setHelperResponder(QObject *o)
00161 {
00162 responder = o;
00163 }
00164
00165 void DBusHelperProxy::remoteSignalReceived(int t, const QString &action, QByteArray blob)
00166 {
00167 SignalType type = (SignalType)t;
00168 QDataStream stream(&blob, QIODevice::ReadOnly);
00169
00170 if (type == ActionStarted) {
00171 emit actionStarted(action);
00172 } else if (type == ActionPerformed) {
00173 ActionReply reply;
00174 stream >> reply;
00175
00176 m_actionsInProgress.removeOne(action);
00177 emit actionPerformed(action, reply);
00178 } else if (type == DebugMessage) {
00179 int level;
00180 QString message;
00181
00182 stream >> level >> message;
00183
00184 debugMessageReceived(level, message);
00185 } else if (type == ProgressStepIndicator) {
00186 int step;
00187 stream >> step;
00188
00189 emit progressStep(action, step);
00190 } else if (type == ProgressStepData) {
00191 QVariantMap data;
00192 stream >> data;
00193
00194 emit progressStep(action, data);
00195 }
00196 }
00197
00198 void DBusHelperProxy::stopAction(const QString &action)
00199 {
00200 #ifndef Q_CC_MSVC
00201 #warning FIXME: The stop request should be action-specific rather than global
00202 #endif
00203 m_stopRequest = true;
00204 }
00205
00206 bool DBusHelperProxy::hasToStopAction()
00207 {
00208 QEventLoop loop;
00209 loop.processEvents(QEventLoop::AllEvents);
00210
00211 return m_stopRequest;
00212 }
00213
00214 void DBusHelperProxy::performActions(QByteArray blob, const QByteArray &callerID)
00215 {
00216 QDataStream stream(&blob, QIODevice::ReadOnly);
00217 QList<QPair<QString, QVariantMap> > actions;
00218
00219 stream >> actions;
00220
00221 QList<QPair<QString, QVariantMap> >::const_iterator i = actions.constBegin();
00222 while (i != actions.constEnd()) {
00223 QByteArray blob;
00224 QDataStream stream(&blob, QIODevice::WriteOnly);
00225
00226 stream << i->second;
00227
00228 emit remoteSignal(ActionPerformed, i->first, performAction(i->first, callerID, blob));
00229
00230 i++;
00231 }
00232 }
00233
00234 QByteArray DBusHelperProxy::performAction(const QString &action, const QByteArray &callerID, QByteArray arguments)
00235 {
00236 if (!responder) {
00237 return ActionReply::NoResponderReply.serialized();
00238 }
00239
00240 if (!m_currentAction.isEmpty()) {
00241 return ActionReply::HelperBusyReply.serialized();
00242 }
00243
00244 QVariantMap args;
00245 QDataStream s(&arguments, QIODevice::ReadOnly);
00246 s >> args;
00247
00248 if (BackendsManager::authBackend()->isCallerAuthorized(action, callerID)) {
00249 QTimer *timer = responder->property("__KAuth_Helper_Shutdown_Timer").value<QTimer*>();
00250 timer->stop();
00251
00252 QString slotname = action;
00253 if (slotname.startsWith(m_name + '.')) {
00254 slotname = slotname.right(slotname.length() - m_name.length() - 1);
00255 }
00256
00257 slotname.replace('.', '_');
00258
00259 ActionReply retVal;
00260
00261 m_currentAction = action;
00262 emit remoteSignal(ActionStarted, action, QByteArray());
00263 bool success = QMetaObject::invokeMethod(responder, slotname.toAscii(), Qt::DirectConnection, Q_RETURN_ARG(ActionReply, retVal), Q_ARG(QVariantMap, args));
00264 emit remoteSignal(ActionPerformed, action, retVal.serialized());
00265 m_currentAction = "";
00266
00267 timer->start();
00268
00269 if (success) {
00270 return retVal.serialized();
00271 } else {
00272 return ActionReply::NoSuchActionReply.serialized();
00273 }
00274
00275 } else {
00276 return ActionReply::AuthorizationDeniedReply.serialized();
00277 }
00278 }
00279
00280 void DBusHelperProxy::sendDebugMessage(int level, const char *msg)
00281 {
00282 QByteArray blob;
00283 QDataStream stream(&blob, QIODevice::WriteOnly);
00284
00285 stream << level << QString(msg);
00286
00287 emit remoteSignal(DebugMessage, m_currentAction, blob);
00288 }
00289
00290 void DBusHelperProxy::sendProgressStep(int step)
00291 {
00292 QByteArray blob;
00293 QDataStream stream(&blob, QIODevice::WriteOnly);
00294
00295 stream << step;
00296
00297 emit remoteSignal(ProgressStepIndicator, m_currentAction, blob);
00298 }
00299
00300 void DBusHelperProxy::sendProgressStep(const QVariantMap &data)
00301 {
00302 QByteArray blob;
00303 QDataStream stream(&blob, QIODevice::WriteOnly);
00304
00305 stream << data;
00306
00307 emit remoteSignal(ProgressStepIndicator, m_currentAction, blob);
00308 }
00309
00310 void debugMessageReceived(int t, const QString &message)
00311 {
00312 QtMsgType type = (QtMsgType)t;
00313 switch (type) {
00314 case QtDebugMsg:
00315 qDebug("Debug message from helper: %s", message.toAscii().data());
00316 break;
00317 case QtWarningMsg:
00318 qWarning("Warning from helper: %s", message.toAscii().data());
00319 break;
00320 case QtCriticalMsg:
00321 qCritical("Critical warning from helper: %s", message.toAscii().data());
00322 break;
00323 case QtFatalMsg:
00324 qFatal("Fatal error from helper: %s", message.toAscii().data());
00325 break;
00326 }
00327 }
00328
00329 }
00330
00331 #ifndef KDE_USE_FINAL
00332 Q_EXPORT_PLUGIN2(helper_proxy, KAuth::DBusHelperProxy)
00333 #endif