File indexing completed on 2024-04-28 09:31:16
0001 /* This file is part of the KDE project 0002 SPDX-FileCopyrightText: 2009 Jaroslav Reznik <jreznik@redhat.com> 0003 SPDX-FileCopyrightText: 2023 Kai Uwe Broulik <kde@broulik.de> 0004 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #include <QDBusConnection> 0009 #include <QDebug> 0010 #include <QGuiApplication> 0011 #include <QQmlEngine> 0012 0013 #include <KLocalizedString> 0014 #include <KWindowSystem> 0015 #include <KX11Extras> 0016 0017 #include <PolkitQt1/ActionDescription> 0018 #include <PolkitQt1/Agent/Session> 0019 #include <PolkitQt1/Details> 0020 #include <PolkitQt1/Identity> 0021 #include <PolkitQt1/Subject> 0022 #include <QDebug> 0023 0024 #include "IdentitiesModel.h" 0025 #include "QuickAuthDialog.h" 0026 #include "policykitlistener.h" 0027 #include "polkit1authagentadaptor.h" 0028 0029 PolicyKitListener::PolicyKitListener(QObject *parent) 0030 : Listener(parent) 0031 , m_inProgress(false) 0032 , m_selectedUser(nullptr) 0033 { 0034 (void)new Polkit1AuthAgentAdaptor(this); 0035 0036 if (!QDBusConnection::sessionBus().registerObject("/org/kde/Polkit1AuthAgent", 0037 this, 0038 QDBusConnection::ExportScriptableSlots | QDBusConnection::ExportScriptableProperties 0039 | QDBusConnection::ExportAdaptors)) { 0040 qWarning() << "Could not initiate DBus helper!"; 0041 } 0042 0043 qmlRegisterType<IdentitiesModel>("org.kde.polkitkde", 1, 0, "IdentitiesModel"); 0044 qmlRegisterUncreatableType<PolkitQt1::ActionDescription>("org.kde.polkitkde", 1, 0, "ActionDescription", "nope!"); 0045 0046 qDebug() << "Listener online"; 0047 } 0048 0049 PolicyKitListener::~PolicyKitListener() 0050 { 0051 } 0052 0053 void PolicyKitListener::setWIdForAction(const QString &action, qulonglong wID) 0054 { 0055 // For compatibility. 0056 setWindowHandleForAction(action, QString::number(wID)); 0057 } 0058 0059 void PolicyKitListener::setWindowHandleForAction(const QString &action, const QString &handle) 0060 { 0061 m_windowHandles[action] = handle; 0062 0063 handleParentWindow(action, handle); 0064 } 0065 0066 void PolicyKitListener::setActivationTokenForAction(const QString &action, const QString &token) 0067 { 0068 if (KWindowSystem::isPlatformWayland()) { 0069 // On X we just forceActivateWindow, no need to store the token. 0070 m_activationTokens[action] = token; 0071 handleWaylandActivation(action, token); 0072 } 0073 } 0074 0075 void PolicyKitListener::initiateAuthentication(const QString &actionId, 0076 const QString &message, 0077 const QString &iconName, 0078 const PolkitQt1::Details &details, 0079 const QString &cookie, 0080 const PolkitQt1::Identity::List &identities, 0081 PolkitQt1::Agent::AsyncResult *result) 0082 { 0083 // The auth action might set any random old icon; all we really want here is a nice 0084 // generic "lock" icon, so we hardcode it and ignore the icon from the auth action. 0085 Q_UNUSED(iconName); 0086 0087 qDebug() << "Initiating authentication"; 0088 0089 if (m_inProgress) { 0090 result->setError(i18n("Another client is already authenticating, please try again later.")); 0091 result->setCompleted(); 0092 qDebug() << "Another client is already authenticating, please try again later."; 0093 return; 0094 } 0095 0096 if (identities.isEmpty()) { 0097 result->setError(i18nc("Error response when polkit calls us with an empty list of identities", "No user to authenticate as. Please check your system configuration.")); 0098 result->setCompleted(); 0099 qWarning() << "No user to authenticate as. Please check your system configuration."; 0100 return; 0101 } 0102 0103 m_identities = identities; 0104 m_cookie = cookie; 0105 m_result = result; 0106 m_session.clear(); 0107 0108 m_inProgress = true; 0109 0110 const QString parentHandle = m_windowHandles.value(actionId); 0111 const QString activationToken = m_activationTokens.value(actionId); 0112 0113 m_dialog = new QuickAuthDialog(actionId, message, details, identities); 0114 0115 if (!parentHandle.isEmpty()) { 0116 handleParentWindow(actionId, parentHandle); 0117 } 0118 0119 connect(m_dialog.data(), SIGNAL(okClicked()), SLOT(dialogAccepted())); 0120 connect(m_dialog.data(), SIGNAL(rejected()), SLOT(dialogCanceled())); 0121 0122 m_dialog->show(); 0123 0124 if (KWindowSystem::isPlatformWayland()) { 0125 if (!activationToken.isEmpty()) { 0126 handleWaylandActivation(actionId, activationToken); 0127 } 0128 } else if (KWindowSystem::isPlatformX11()) { 0129 KX11Extras::forceActiveWindow(m_dialog->windowHandle()->winId()); 0130 } 0131 0132 if (identities.length() == 1) { 0133 m_selectedUser = identities[0]; 0134 } else { 0135 m_selectedUser = m_dialog.data()->adminUserSelected(); 0136 } 0137 0138 m_numTries = 0; 0139 tryAgain(); 0140 } 0141 0142 void PolicyKitListener::handleParentWindow(const QString &action, const QString &handle) 0143 { 0144 if (!m_dialog || m_dialog->actionId() != action) { 0145 return; 0146 } 0147 0148 KWindowSystem::setMainWindow(m_dialog->windowHandle(), handle); 0149 } 0150 0151 void PolicyKitListener::handleWaylandActivation(const QString &action, const QString &token) 0152 { 0153 if (!m_dialog || m_dialog->actionId() != action) { 0154 return; 0155 } 0156 0157 qputenv("XDG_ACTIVATION_TOKEN", token.toUtf8()); 0158 m_dialog->windowHandle()->requestActivate(); 0159 } 0160 0161 void PolicyKitListener::tryAgain() 0162 { 0163 qDebug() << "Trying again"; 0164 m_wasCancelled = false; 0165 0166 // We will create new session only when some user is selected 0167 if (m_selectedUser.isValid()) { 0168 m_session = new Session(m_selectedUser, m_cookie, m_result); 0169 // clang-format off 0170 connect(m_session.data(), SIGNAL(request(QString,bool)), this, SLOT(request(QString,bool))); 0171 connect(m_session.data(), SIGNAL(completed(bool)), this, SLOT(completed(bool))); 0172 connect(m_session.data(), SIGNAL(showError(QString)), this, SLOT(showError(QString))); 0173 connect(m_session.data(), SIGNAL(showInfo(QString)), this, SLOT(showInfo(QString))); 0174 // clang-format on 0175 0176 m_session.data()->initiate(); 0177 } 0178 } 0179 0180 void PolicyKitListener::finishObtainPrivilege() 0181 { 0182 qDebug() << "Finishing obtaining privileges"; 0183 0184 // Number of tries increase only when some user is selected 0185 if (m_selectedUser.isValid()) { 0186 m_numTries++; 0187 } 0188 0189 if (!m_gainedAuthorization && !m_wasCancelled && !m_dialog.isNull()) { 0190 m_dialog.data()->authenticationFailure(); 0191 0192 if (m_numTries < 3) { 0193 m_session.data()->deleteLater(); 0194 0195 tryAgain(); 0196 return; 0197 } 0198 } 0199 0200 if (!m_session.isNull()) { 0201 m_session.data()->result()->setCompleted(); 0202 } else { 0203 m_result->setCompleted(); 0204 } 0205 m_session.data()->deleteLater(); 0206 0207 if (!m_dialog.isNull()) { 0208 m_dialog.data()->hide(); 0209 m_dialog.data()->deleteLater(); 0210 } 0211 0212 m_inProgress = false; 0213 0214 qDebug() << "Finish obtain authorization:" << m_gainedAuthorization; 0215 } 0216 0217 bool PolicyKitListener::initiateAuthenticationFinish() 0218 { 0219 qDebug() << "Finishing authentication"; 0220 return true; 0221 } 0222 0223 void PolicyKitListener::cancelAuthentication() 0224 { 0225 qDebug() << "Cancelling authentication"; 0226 0227 m_wasCancelled = true; 0228 finishObtainPrivilege(); 0229 } 0230 0231 void PolicyKitListener::request(const QString &request, bool echo) 0232 { 0233 Q_UNUSED(echo); 0234 qDebug() << "Request: " << request; 0235 } 0236 0237 void PolicyKitListener::completed(bool gainedAuthorization) 0238 { 0239 qDebug() << "Completed: " << gainedAuthorization; 0240 0241 m_gainedAuthorization = gainedAuthorization; 0242 0243 finishObtainPrivilege(); 0244 } 0245 0246 void PolicyKitListener::showError(const QString &text) 0247 { 0248 qDebug() << "Error: " << text; 0249 if (!m_dialog.isNull()) { 0250 m_dialog.data()->showError(text); 0251 } 0252 } 0253 0254 void PolicyKitListener::showInfo(const QString &text) 0255 { 0256 qDebug() << "Info: " << text; 0257 if (!m_dialog.isNull()) { 0258 m_dialog.data()->showInfo(text); 0259 } 0260 } 0261 0262 void PolicyKitListener::dialogAccepted() 0263 { 0264 qDebug() << "Dialog accepted"; 0265 0266 if (!m_session.isNull() && !m_dialog.isNull()) { 0267 m_session.data()->setResponse(m_dialog.data()->password()); 0268 } 0269 } 0270 0271 void PolicyKitListener::dialogCanceled() 0272 { 0273 qDebug() << "Dialog cancelled"; 0274 0275 m_wasCancelled = true; 0276 if (!m_session.isNull()) { 0277 m_session.data()->cancel(); 0278 } 0279 0280 finishObtainPrivilege(); 0281 } 0282 0283 void PolicyKitListener::userSelected(const PolkitQt1::Identity &identity) 0284 { 0285 m_selectedUser = identity; 0286 // If some user is selected we must destroy existing session 0287 if (!m_session.isNull()) { 0288 m_session.data()->deleteLater(); 0289 } 0290 tryAgain(); 0291 } 0292 0293 #include "moc_policykitlistener.cpp"