KDECore
DBusHelperProxy.cpp
Go to the documentation of this file.
00001 /* 00002 * Copyright (C) 2008 Nicola Gigante <nicola.gigante@gmail.com> 00003 * Copyright (C) 2009-2010 Dario Freddi <drf@kde.org> 00004 * 00005 * This program is free software; you can redistribute it and/or modify 00006 * it under the terms of the GNU Lesser General Public License as published by 00007 * the Free Software Foundation; either version 2.1 of the License, or 00008 * (at your option) any later version. 00009 * 00010 * This program is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 * GNU General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU Lesser General Public License 00016 * along with this program; if not, write to the 00017 * Free Software Foundation, Inc., 00018 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . 00019 */ 00020 00021 #include "DBusHelperProxy.h" 00022 00023 #include <QtCore/qplugin.h> 00024 #include <QObject> 00025 #include <QMap> 00026 #include <QtDBus/QDBusMessage> 00027 #include <QtDBus/QDBusConnection> 00028 #include <QDebug> 00029 #include <QTimer> 00030 00031 #include <klocalizedstring.h> 00032 00033 #include <syslog.h> 00034 00035 #include "BackendsManager.h" 00036 #include "authadaptor.h" 00037 00038 Q_DECLARE_METATYPE(QTimer*) 00039 00040 namespace KAuth 00041 { 00042 00043 static void debugMessageReceived(int t, const QString &message); 00044 00045 void DBusHelperProxy::stopAction(const QString &action, const QString &helperID) 00046 { 00047 QDBusMessage message; 00048 message = QDBusMessage::createMethodCall(helperID, QLatin1String("/"), QLatin1String("org.kde.auth"), QLatin1String("stopAction")); 00049 00050 QList<QVariant> args; 00051 args << action; 00052 message.setArguments(args); 00053 00054 QDBusConnection::systemBus().asyncCall(message); 00055 } 00056 00057 bool DBusHelperProxy::executeActions(const QList<QPair<QString, QVariantMap> > &list, const QString &helperID) 00058 { 00059 QByteArray blob; 00060 QDataStream stream(&blob, QIODevice::WriteOnly); 00061 00062 stream << list; 00063 00064 QDBusConnection::systemBus().interface()->startService(helperID); 00065 00066 if (!QDBusConnection::systemBus().connect(helperID, QLatin1String("/"), QLatin1String("org.kde.auth"), QLatin1String("remoteSignal"), this, SLOT(remoteSignalReceived(int, const QString &, QByteArray)))) { 00067 return false; 00068 } 00069 00070 QDBusMessage message; 00071 message = QDBusMessage::createMethodCall(helperID, QLatin1String("/"), QLatin1String("org.kde.auth"), QLatin1String("performActions")); 00072 00073 QList<QVariant> args; 00074 args << blob << BackendsManager::authBackend()->callerID(); 00075 message.setArguments(args); 00076 00077 QDBusPendingCall reply = QDBusConnection::systemBus().asyncCall(message); // This is a NO_REPLY method 00078 if (reply.reply().type() == QDBusMessage::ErrorMessage) { 00079 return false; 00080 } 00081 00082 return true; 00083 } 00084 00085 ActionReply DBusHelperProxy::executeAction(const QString &action, const QString &helperID, const QVariantMap &arguments) 00086 { 00087 if (!m_actionsInProgress.isEmpty()) { 00088 return ActionReply::HelperBusyReply; 00089 } 00090 00091 QByteArray blob; 00092 QDataStream stream(&blob, QIODevice::WriteOnly); 00093 00094 stream << arguments; 00095 00096 QDBusConnection::systemBus().interface()->startService(helperID); 00097 00098 if (!QDBusConnection::systemBus().connect(helperID, QLatin1String("/"), QLatin1String("org.kde.auth"), QLatin1String("remoteSignal"), this, SLOT(remoteSignalReceived(int, const QString &, QByteArray)))) { 00099 ActionReply errorReply = ActionReply::DBusErrorReply; 00100 errorReply.setErrorDescription(i18n("DBus Backend error: connection to helper failed. %1", 00101 QDBusConnection::systemBus().lastError().message())); 00102 return errorReply; 00103 } 00104 00105 QDBusMessage message; 00106 message = QDBusMessage::createMethodCall(helperID, QLatin1String("/"), QLatin1String("org.kde.auth"), QLatin1String("performAction")); 00107 00108 QList<QVariant> args; 00109 args << action << BackendsManager::authBackend()->callerID() << blob; 00110 message.setArguments(args); 00111 00112 m_actionsInProgress.push_back(action); 00113 00114 QEventLoop e; 00115 QDBusPendingCall pendingCall = QDBusConnection::systemBus().asyncCall(message); 00116 QDBusPendingCallWatcher watcher(pendingCall, this); 00117 connect(&watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), &e, SLOT(quit())); 00118 e.exec(); 00119 00120 QDBusMessage reply = pendingCall.reply(); 00121 00122 if (reply.type() == QDBusMessage::ErrorMessage) { 00123 ActionReply r = ActionReply::DBusErrorReply; 00124 r.setErrorDescription(i18n("DBus Backend error: could not contact the helper. " 00125 "Connection error: %1. Message error: %2", QDBusConnection::systemBus().lastError().message(), 00126 reply.errorMessage())); 00127 qDebug() << reply.errorMessage(); 00128 00129 // The remote signal will never arrive: so let's erase the action from the list ourselves 00130 m_actionsInProgress.removeOne(action); 00131 00132 return r; 00133 } 00134 00135 if (reply.arguments().size() != 1) { 00136 ActionReply errorReply = ActionReply::DBusErrorReply; 00137 errorReply.setErrorDescription(i18n("DBus Backend error: received corrupt data from helper %1 %2", 00138 reply.arguments().size(), QDBusConnection::systemBus().lastError().message())); 00139 00140 // The remote signal may never arrive: so let's erase the action from the list ourselves 00141 m_actionsInProgress.removeOne(action); 00142 00143 return errorReply; 00144 } 00145 00146 return ActionReply::deserialize(reply.arguments().first().toByteArray()); 00147 } 00148 00149 Action::AuthStatus DBusHelperProxy::authorizeAction(const QString& action, const QString& helperID) 00150 { 00151 if (!m_actionsInProgress.isEmpty()) { 00152 return Action::Error; 00153 } 00154 00155 QDBusConnection::systemBus().interface()->startService(helperID); 00156 00157 QDBusMessage message; 00158 message = QDBusMessage::createMethodCall(helperID, QLatin1String("/"), QLatin1String("org.kde.auth"), QLatin1String("authorizeAction")); 00159 00160 QList<QVariant> args; 00161 args << action << BackendsManager::authBackend()->callerID(); 00162 message.setArguments(args); 00163 00164 m_actionsInProgress.push_back(action); 00165 00166 QEventLoop e; 00167 QDBusPendingCall pendingCall = QDBusConnection::systemBus().asyncCall(message); 00168 QDBusPendingCallWatcher watcher(pendingCall, this); 00169 connect(&watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), &e, SLOT(quit())); 00170 e.exec(); 00171 00172 m_actionsInProgress.removeOne(action); 00173 00174 QDBusMessage reply = pendingCall.reply(); 00175 00176 if (reply.type() == QDBusMessage::ErrorMessage || reply.arguments().size() != 1) { 00177 return Action::Error; 00178 } 00179 00180 return static_cast<Action::AuthStatus>(reply.arguments().first().toUInt()); 00181 } 00182 00183 bool DBusHelperProxy::initHelper(const QString &name) 00184 { 00185 new AuthAdaptor(this); 00186 00187 if (!QDBusConnection::systemBus().registerService(name)) { 00188 return false; 00189 } 00190 00191 if (!QDBusConnection::systemBus().registerObject(QLatin1String("/"), this)) { 00192 return false; 00193 } 00194 00195 m_name = name; 00196 00197 return true; 00198 } 00199 00200 void DBusHelperProxy::setHelperResponder(QObject *o) 00201 { 00202 responder = o; 00203 } 00204 00205 void DBusHelperProxy::remoteSignalReceived(int t, const QString &action, QByteArray blob) 00206 { 00207 SignalType type = (SignalType)t; 00208 QDataStream stream(&blob, QIODevice::ReadOnly); 00209 00210 if (type == ActionStarted) { 00211 emit actionStarted(action); 00212 } else if (type == ActionPerformed) { 00213 ActionReply reply = ActionReply::deserialize(blob); 00214 00215 m_actionsInProgress.removeOne(action); 00216 emit actionPerformed(action, reply); 00217 } else if (type == DebugMessage) { 00218 int level; 00219 QString message; 00220 00221 stream >> level >> message; 00222 00223 debugMessageReceived(level, message); 00224 } else if (type == ProgressStepIndicator) { 00225 int step; 00226 stream >> step; 00227 00228 emit progressStep(action, step); 00229 } else if (type == ProgressStepData) { 00230 QVariantMap data; 00231 stream >> data; 00232 00233 emit progressStep(action, data); 00234 } 00235 } 00236 00237 void DBusHelperProxy::stopAction(const QString &action) 00238 { 00239 Q_UNUSED(action) 00240 #ifdef __GNUC__ 00241 #warning FIXME: The stop request should be action-specific rather than global 00242 #endif 00243 m_stopRequest = true; 00244 } 00245 00246 bool DBusHelperProxy::hasToStopAction() 00247 { 00248 QEventLoop loop; 00249 loop.processEvents(QEventLoop::AllEvents); 00250 00251 return m_stopRequest; 00252 } 00253 00254 void DBusHelperProxy::performActions(QByteArray blob, const QByteArray &callerID) 00255 { 00256 QDataStream stream(&blob, QIODevice::ReadOnly); 00257 QList< QPair< QString, QVariantMap > > actions; 00258 00259 stream >> actions; 00260 00261 QList< QPair< QString, QVariantMap > >::const_iterator i = actions.constBegin(); 00262 while (i != actions.constEnd()) { 00263 QByteArray blob; 00264 QDataStream stream(&blob, QIODevice::WriteOnly); 00265 00266 stream << i->second; 00267 00268 performAction(i->first, callerID, blob); 00269 00270 i++; 00271 } 00272 } 00273 00274 QByteArray DBusHelperProxy::performAction(const QString &action, const QByteArray &callerID, QByteArray arguments) 00275 { 00276 if (!responder) { 00277 return ActionReply::NoResponderReply.serialized(); 00278 } 00279 00280 if (!m_currentAction.isEmpty()) { 00281 return ActionReply::HelperBusyReply.serialized(); 00282 } 00283 00284 QVariantMap args; 00285 QDataStream s(&arguments, QIODevice::ReadOnly); 00286 s >> args; 00287 00288 m_currentAction = action; 00289 emit remoteSignal(ActionStarted, action, QByteArray()); 00290 QEventLoop e; 00291 e.processEvents(QEventLoop::AllEvents); 00292 00293 ActionReply retVal; 00294 00295 QTimer *timer = responder->property("__KAuth_Helper_Shutdown_Timer").value<QTimer*>(); 00296 timer->stop(); 00297 00298 if (BackendsManager::authBackend()->isCallerAuthorized(action, callerID)) { 00299 QString slotname = action; 00300 if (slotname.startsWith(m_name + QLatin1Char('.'))) { 00301 slotname = slotname.right(slotname.length() - m_name.length() - 1); 00302 } 00303 00304 slotname.replace(QLatin1Char('.'), QLatin1Char('_')); 00305 00306 bool success = QMetaObject::invokeMethod(responder, slotname.toAscii(), Qt::DirectConnection, 00307 Q_RETURN_ARG(ActionReply, retVal), Q_ARG(QVariantMap, args)); 00308 00309 if (!success) { 00310 retVal = ActionReply::NoSuchActionReply; 00311 } 00312 00313 } else { 00314 retVal = ActionReply::AuthorizationDeniedReply; 00315 } 00316 00317 timer->start(); 00318 00319 emit remoteSignal(ActionPerformed, action, retVal.serialized()); 00320 e.processEvents(QEventLoop::AllEvents); 00321 m_currentAction.clear(); 00322 m_stopRequest = false; 00323 00324 return retVal.serialized(); 00325 } 00326 00327 00328 uint DBusHelperProxy::authorizeAction(const QString& action, const QByteArray& callerID) 00329 { 00330 if (!m_currentAction.isEmpty()) { 00331 return static_cast<uint>(Action::Error); 00332 } 00333 00334 m_currentAction = action; 00335 00336 uint retVal; 00337 00338 QTimer *timer = responder->property("__KAuth_Helper_Shutdown_Timer").value<QTimer*>(); 00339 timer->stop(); 00340 00341 if (BackendsManager::authBackend()->isCallerAuthorized(action, callerID)) { 00342 retVal = static_cast<uint>(Action::Authorized); 00343 } else { 00344 retVal = static_cast<uint>(Action::Denied); 00345 } 00346 00347 timer->start(); 00348 m_currentAction.clear(); 00349 00350 return retVal; 00351 } 00352 00353 00354 void DBusHelperProxy::sendDebugMessage(int level, const char *msg) 00355 { 00356 QByteArray blob; 00357 QDataStream stream(&blob, QIODevice::WriteOnly); 00358 00359 stream << level << QString::fromLocal8Bit(msg); 00360 00361 emit remoteSignal(DebugMessage, m_currentAction, blob); 00362 } 00363 00364 void DBusHelperProxy::sendProgressStep(int step) 00365 { 00366 QByteArray blob; 00367 QDataStream stream(&blob, QIODevice::WriteOnly); 00368 00369 stream << step; 00370 00371 emit remoteSignal(ProgressStepIndicator, m_currentAction, blob); 00372 } 00373 00374 void DBusHelperProxy::sendProgressStep(const QVariantMap &data) 00375 { 00376 QByteArray blob; 00377 QDataStream stream(&blob, QIODevice::WriteOnly); 00378 00379 stream << data; 00380 00381 emit remoteSignal(ProgressStepData, m_currentAction, blob); 00382 } 00383 00384 void debugMessageReceived(int t, const QString &message) 00385 { 00386 QtMsgType type = (QtMsgType)t; 00387 switch (type) { 00388 case QtDebugMsg: 00389 qDebug("Debug message from helper: %s", message.toAscii().data()); 00390 break; 00391 case QtWarningMsg: 00392 qWarning("Warning from helper: %s", message.toAscii().data()); 00393 break; 00394 case QtCriticalMsg: 00395 qCritical("Critical warning from helper: %s", message.toAscii().data()); 00396 break; 00397 case QtFatalMsg: 00398 qFatal("Fatal error from helper: %s", message.toAscii().data()); 00399 break; 00400 } 00401 } 00402 00403 } // namespace Auth 00404 00405 Q_EXPORT_PLUGIN2(kauth_helper_backend, KAuth::DBusHelperProxy)
KDE 4.6 API Reference