KDECore
Polkit1Backend.cpp
Go to the documentation of this file.
00001 /* 00002 * Copyright (C) 2008 Nicola Gigante <nicola.gigante@gmail.com> 00003 * Copyright (C) 2009 Radek Novacek <rnovacek@redhat.com> 00004 * Copyright (C) 2009-2010 Dario Freddi <drf@kde.org> 00005 * 00006 * This program is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU Lesser General Public License as published by 00008 * the Free Software Foundation; either version 2.1 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU Lesser General Public License 00017 * along with this program; if not, write to the 00018 * Free Software Foundation, Inc., 00019 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . 00020 */ 00021 00022 #include "Polkit1Backend.h" 00023 00024 #include <QtCore/qplugin.h> 00025 #include <QtCore/QCoreApplication> 00026 #include <QtCore/QTimer> 00027 00028 #include <QtGui/QApplication> 00029 #include <QtGui/QWidget> 00030 00031 #include <QtDBus/QDBusConnection> 00032 #include <QtDBus/QDBusConnectionInterface> 00033 00034 #include <kdebug.h> 00035 00036 #include <PolkitQt1/Authority> 00037 #include <PolkitQt1/Subject> 00038 00039 namespace KAuth 00040 { 00041 00042 PolkitResultEventLoop::PolkitResultEventLoop(QObject* parent) 00043 : QEventLoop(parent) 00044 { 00045 } 00046 00047 PolkitResultEventLoop::~PolkitResultEventLoop() 00048 { 00049 } 00050 00051 void PolkitResultEventLoop::requestQuit(const PolkitQt1::Authority::Result& result) 00052 { 00053 m_result = result; 00054 quit(); 00055 } 00056 00057 PolkitQt1::Authority::Result PolkitResultEventLoop::result() const 00058 { 00059 return m_result; 00060 } 00061 00062 Polkit1Backend::Polkit1Backend() 00063 : AuthBackend() 00064 , m_flyingActions(false) 00065 { 00066 setCapabilities(AuthorizeFromHelperCapability | CheckActionExistenceCapability | PreAuthActionCapability); 00067 00068 // Setup useful signals 00069 connect(PolkitQt1::Authority::instance(), SIGNAL(configChanged()), 00070 this, SLOT(checkForResultChanged())); 00071 connect(PolkitQt1::Authority::instance(), SIGNAL(consoleKitDBChanged()), 00072 this, SLOT(checkForResultChanged())); 00073 connect(PolkitQt1::Authority::instance(), SIGNAL(enumerateActionsFinished(PolkitQt1::ActionDescription::List)), 00074 this, SLOT(updateCachedActions(PolkitQt1::ActionDescription::List))); 00075 00076 // Cache existing action IDs as soon as possible 00077 m_flyingActions = true; 00078 PolkitQt1::Authority::instance()->enumerateActions(); 00079 } 00080 00081 Polkit1Backend::~Polkit1Backend() 00082 { 00083 00084 } 00085 00086 void Polkit1Backend::preAuthAction(const QString& action, QWidget* parent) 00087 { 00088 kDebug(); 00089 // If a parent was not specified, skip this 00090 if (!parent) { 00091 kDebug() << "Parent widget does not exist, skipping"; 00092 return; 00093 } 00094 00095 // Are we running our KDE auth agent? 00096 if (QDBusConnection::sessionBus().interface()->isServiceRegistered(QLatin1String("org.kde.Polkit1AuthAgent"))) { 00097 // Check if we actually are entitled to use GUI capabilities 00098 if (qApp == 0 || QApplication::type() == QApplication::Tty) { 00099 kDebug() << "Not streaming parent as we are on a TTY application"; 00100 } 00101 00102 // Retrieve the dialog root window Id 00103 qulonglong wId = parent->effectiveWinId(); 00104 00105 // Send it over the bus to our agent 00106 QDBusMessage methodCall = 00107 QDBusMessage::createMethodCall(QLatin1String("org.kde.Polkit1AuthAgent"), QLatin1String("/org/kde/Polkit1AuthAgent"), QLatin1String("org.kde.Polkit1AuthAgent"), 00108 QLatin1String("setWIdForAction")); 00109 00110 methodCall << action; 00111 methodCall << wId; 00112 00113 QDBusPendingCall call = QDBusConnection::sessionBus().asyncCall(methodCall); 00114 call.waitForFinished(); 00115 00116 if (call.isError()) { 00117 kWarning() << "ERROR while streaming the parent!!" << call.error(); 00118 } 00119 } else { 00120 kDebug() << "KDE polkit agent appears too old or not registered on the bus"; 00121 } 00122 } 00123 00124 void Polkit1Backend::updateCachedActions(const PolkitQt1::ActionDescription::List& actions) 00125 { 00126 m_knownActions.clear(); 00127 foreach (const PolkitQt1::ActionDescription& action, actions) { 00128 m_knownActions << action.actionId(); 00129 } 00130 m_flyingActions = false; 00131 } 00132 00133 Action::AuthStatus Polkit1Backend::authorizeAction(const QString &action) 00134 { 00135 Q_UNUSED(action) 00136 // Always return Yes here, we'll authorize inside isCallerAuthorized 00137 return Action::Authorized; 00138 } 00139 00140 void Polkit1Backend::setupAction(const QString &action) 00141 { 00142 m_cachedResults[action] = actionStatus(action); 00143 } 00144 00145 Action::AuthStatus Polkit1Backend::actionStatus(const QString &action) 00146 { 00147 PolkitQt1::UnixProcessSubject subject(QCoreApplication::applicationPid()); 00148 PolkitQt1::Authority::Result r = PolkitQt1::Authority::instance()->checkAuthorizationSync(action, subject, 00149 PolkitQt1::Authority::None); 00150 switch (r) { 00151 case PolkitQt1::Authority::Yes: 00152 return Action::Authorized; 00153 case PolkitQt1::Authority::No: 00154 case PolkitQt1::Authority::Unknown: 00155 return Action::Denied; 00156 default: 00157 return Action::AuthRequired; 00158 } 00159 } 00160 00161 QByteArray Polkit1Backend::callerID() const 00162 { 00163 QByteArray a; 00164 QDataStream s(&a, QIODevice::WriteOnly); 00165 s << QCoreApplication::applicationPid(); 00166 00167 return a; 00168 } 00169 00170 bool Polkit1Backend::isCallerAuthorized(const QString &action, QByteArray callerID) 00171 { 00172 QDataStream s(&callerID, QIODevice::ReadOnly); 00173 qint64 pid; 00174 00175 s >> pid; 00176 00177 PolkitQt1::UnixProcessSubject subject(pid); 00178 PolkitQt1::Authority *authority = PolkitQt1::Authority::instance(); 00179 00180 PolkitResultEventLoop e; 00181 connect(authority, SIGNAL(checkAuthorizationFinished(PolkitQt1::Authority::Result)), 00182 &e, SLOT(requestQuit(PolkitQt1::Authority::Result))); 00183 authority->checkAuthorization(action, subject, PolkitQt1::Authority::AllowUserInteraction); 00184 e.exec(); 00185 00186 switch (e.result()) { 00187 case PolkitQt1::Authority::Yes: 00188 return true; 00189 default: 00190 return false; 00191 } 00192 00193 return false; 00194 } 00195 00196 void Polkit1Backend::checkForResultChanged() 00197 { 00198 foreach(const QString &action, m_cachedResults.keys()) { 00199 if (m_cachedResults[action] != actionStatus(action)) { 00200 m_cachedResults[action] = actionStatus(action); 00201 emit actionStatusChanged(action, m_cachedResults[action]); 00202 } 00203 } 00204 00205 // Force updating known actions 00206 PolkitQt1::Authority::instance()->enumerateActions(); 00207 m_flyingActions = true; 00208 } 00209 00210 bool Polkit1Backend::actionExists(const QString& action) 00211 { 00212 // Any flying actions? 00213 if (m_flyingActions) { 00214 int tries = 0; 00215 while (m_flyingActions && tries < 10) { 00216 // Wait max 2 seconds 00217 QEventLoop e; 00218 QTimer::singleShot(200, &e, SLOT(quit())); 00219 e.exec(); 00220 ++tries; 00221 } 00222 } 00223 00224 return m_knownActions.contains(action); 00225 } 00226 00227 } // namespace Auth 00228 00229 Q_EXPORT_PLUGIN2(kauth_backend, KAuth::Polkit1Backend)
KDE 4.6 API Reference