File indexing completed on 2024-05-05 16:05:15
0001 /* 0002 SPDX-FileCopyrightText: 2008 Nicola Gigante <nicola.gigante@gmail.com> 0003 SPDX-FileCopyrightText: 2009 Radek Novacek <rnovacek@redhat.com> 0004 SPDX-FileCopyrightText: 2009-2010 Dario Freddi <drf@kde.org> 0005 SPDX-FileCopyrightText: 2020 David Edmundson <davidedmundson@kde.org> 0006 0007 SPDX-License-Identifier: LGPL-2.1-or-later 0008 */ 0009 0010 #include "Polkit1Backend.h" 0011 #include "kauthdebug.h" 0012 0013 #include <QCoreApplication> 0014 #include <QTimer> 0015 #include <qplugin.h> 0016 0017 #include <QApplication> 0018 #include <QWidget> 0019 0020 #include <QDBusConnection> 0021 #include <QDBusConnectionInterface> 0022 0023 #include <PolkitQt1/Subject> 0024 #include <polkitqt1-version.h> 0025 0026 namespace KAuth 0027 { 0028 Polkit1Backend::Polkit1Backend() 0029 : AuthBackend() 0030 { 0031 setCapabilities(AuthorizeFromHelperCapability | CheckActionExistenceCapability | PreAuthActionCapability); 0032 0033 // Setup useful signals 0034 connect(PolkitQt1::Authority::instance(), &PolkitQt1::Authority::configChanged, this, &KAuth::Polkit1Backend::checkForResultChanged); 0035 connect(PolkitQt1::Authority::instance(), &PolkitQt1::Authority::consoleKitDBChanged, this, &KAuth::Polkit1Backend::checkForResultChanged); 0036 } 0037 0038 Polkit1Backend::~Polkit1Backend() 0039 { 0040 } 0041 0042 void Polkit1Backend::preAuthAction(const QString &action, QWidget *parent) 0043 { 0044 // If a parent was not specified, skip this 0045 if (!parent) { 0046 qCDebug(KAUTH) << "Parent widget does not exist, skipping"; 0047 return; 0048 } 0049 0050 // Are we running our KDE auth agent? 0051 if (QDBusConnection::sessionBus().interface()->isServiceRegistered(QLatin1String("org.kde.polkit-kde-authentication-agent-1"))) { 0052 // Check if we actually are entitled to use GUI capabilities 0053 if (qApp == nullptr || !qobject_cast<QApplication *>(qApp)) { 0054 qCDebug(KAUTH) << "Not streaming parent as we are on a TTY application"; 0055 } 0056 0057 // Retrieve the dialog root window Id 0058 qulonglong wId = parent->effectiveWinId(); 0059 0060 // Send it over the bus to our agent 0061 QDBusMessage methodCall = QDBusMessage::createMethodCall(QLatin1String("org.kde.polkit-kde-authentication-agent-1"), 0062 QLatin1String("/org/kde/Polkit1AuthAgent"), 0063 QLatin1String("org.kde.Polkit1AuthAgent"), 0064 QLatin1String("setWIdForAction")); 0065 0066 methodCall << action; 0067 methodCall << wId; 0068 0069 QDBusPendingCall call = QDBusConnection::sessionBus().asyncCall(methodCall); 0070 call.waitForFinished(); 0071 0072 if (call.isError()) { 0073 qCWarning(KAUTH) << "ERROR while streaming the parent!!" << call.error(); 0074 } 0075 } else { 0076 qCDebug(KAUTH) << "KDE polkit agent appears too old or not registered on the bus"; 0077 } 0078 } 0079 0080 Action::AuthStatus Polkit1Backend::authorizeAction(const QString &action) 0081 { 0082 Q_UNUSED(action) 0083 // Always return Yes here, we'll authorize inside isCallerAuthorized 0084 return Action::AuthorizedStatus; 0085 } 0086 0087 void Polkit1Backend::setupAction(const QString &action) 0088 { 0089 m_cachedResults[action] = actionStatus(action); 0090 } 0091 0092 Action::AuthStatus Polkit1Backend::actionStatus(const QString &action) 0093 { 0094 PolkitQt1::SystemBusNameSubject subject(QString::fromUtf8(callerID())); 0095 auto authority = PolkitQt1::Authority::instance(); 0096 PolkitQt1::Authority::Result r = authority->checkAuthorizationSync(action, subject, PolkitQt1::Authority::None); 0097 0098 if (authority->hasError()) { 0099 qCDebug(KAUTH) << "Encountered error while checking action status, error code:" << authority->lastError() << authority->errorDetails(); 0100 authority->clearError(); 0101 return Action::InvalidStatus; 0102 } 0103 0104 switch (r) { 0105 case PolkitQt1::Authority::Yes: 0106 return Action::AuthorizedStatus; 0107 case PolkitQt1::Authority::No: 0108 case PolkitQt1::Authority::Unknown: 0109 return Action::DeniedStatus; 0110 default: 0111 return Action::AuthRequiredStatus; 0112 } 0113 } 0114 0115 QByteArray Polkit1Backend::callerID() const 0116 { 0117 return QDBusConnection::systemBus().baseService().toUtf8(); 0118 } 0119 0120 AuthBackend::ExtraCallerIDVerificationMethod Polkit1Backend::extraCallerIDVerificationMethod() const 0121 { 0122 return VerifyAgainstDBusServiceName; 0123 } 0124 0125 bool Polkit1Backend::isCallerAuthorized(const QString &action, const QByteArray &callerID, const QVariantMap &details) 0126 { 0127 PolkitQt1::SystemBusNameSubject subject(QString::fromUtf8(callerID)); 0128 PolkitQt1::Authority *authority = PolkitQt1::Authority::instance(); 0129 QMap<QString, QString> polkit1Details; 0130 for (auto it = details.cbegin(); it != details.cend(); ++it) { 0131 polkit1Details.insert(it.key(), it.value().toString()); 0132 } 0133 0134 PolkitQt1::Authority::Result result; 0135 QEventLoop e; 0136 connect(authority, &PolkitQt1::Authority::checkAuthorizationFinished, &e, [&result, &e](PolkitQt1::Authority::Result _result) { 0137 result = _result; 0138 e.quit(); 0139 }); 0140 0141 #if POLKITQT1_IS_VERSION(0, 113, 0) 0142 authority->checkAuthorizationWithDetails(action, subject, PolkitQt1::Authority::AllowUserInteraction, polkit1Details); 0143 #else 0144 authority->checkAuthorization(action, subject, PolkitQt1::Authority::AllowUserInteraction); 0145 #endif 0146 e.exec(); 0147 0148 if (authority->hasError()) { 0149 qCDebug(KAUTH) << "Encountered error while checking authorization, error code:" << authority->lastError() << authority->errorDetails(); 0150 authority->clearError(); 0151 } 0152 0153 switch (result) { 0154 case PolkitQt1::Authority::Yes: 0155 return true; 0156 default: 0157 return false; 0158 } 0159 } 0160 0161 void Polkit1Backend::checkForResultChanged() 0162 { 0163 for (auto it = m_cachedResults.begin(); it != m_cachedResults.end(); ++it) { 0164 const QString action = it.key(); 0165 if (it.value() != actionStatus(action)) { 0166 *it = actionStatus(action); 0167 Q_EMIT actionStatusChanged(action, *it); 0168 } 0169 } 0170 } 0171 0172 bool Polkit1Backend::actionExists(const QString &action) 0173 { 0174 return m_cachedResults.value(action) != Action::InvalidStatus; 0175 } 0176 0177 QVariantMap Polkit1Backend::backendDetails(const DetailsMap &details) 0178 { 0179 QVariantMap backendDetails; 0180 for (auto it = details.cbegin(); it != details.cend(); ++it) { 0181 switch (it.key()) { 0182 case Action::AuthDetail::DetailMessage: 0183 backendDetails.insert(QStringLiteral("polkit.message"), it.value()); 0184 break; 0185 case Action::AuthDetail::DetailOther: 0186 default: 0187 backendDetails.insert(QStringLiteral("other_details"), it.value()); 0188 break; 0189 } 0190 } 0191 return backendDetails; 0192 } 0193 0194 } // namespace Auth 0195 0196 #include "moc_Polkit1Backend.cpp"