File indexing completed on 2024-12-08 06:37:39
0001 /* 0002 SPDX-FileCopyrightText: 2009-2012 Dario Freddi <drf@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.1-or-later 0005 */ 0006 0007 #include "executejob.h" 0008 0009 #include "BackendsManager.h" 0010 #include "kauthdebug.h" 0011 0012 #include <QCoreApplication> 0013 #include <QEventLoop> 0014 #include <QHash> 0015 #include <QTimer> 0016 0017 namespace KAuth 0018 { 0019 class ExecuteJobPrivate 0020 { 0021 Q_DECLARE_TR_FUNCTIONS(KAuth::ExecuteJob) 0022 0023 public: 0024 explicit ExecuteJobPrivate(ExecuteJob *parent) 0025 : q(parent) 0026 { 0027 } 0028 0029 ExecuteJob *q; 0030 Action action; 0031 0032 Action::ExecutionMode mode; 0033 QVariantMap data; 0034 0035 void doExecuteAction(); 0036 void doAuthorizeAction(); 0037 void actionPerformedSlot(const QString &action, const ActionReply &reply); 0038 void progressStepSlot(const QString &action, int i); 0039 void progressStepSlot(const QString &action, const QVariantMap &data); 0040 void statusChangedSlot(const QString &action, KAuth::Action::AuthStatus status); 0041 }; 0042 0043 ExecuteJob::ExecuteJob(const Action &action, Action::ExecutionMode mode, QObject *parent) 0044 : KJob(parent) 0045 , d(new ExecuteJobPrivate(this)) 0046 { 0047 d->action = action; 0048 d->mode = mode; 0049 0050 HelperProxy *helper = BackendsManager::helperProxy(); 0051 0052 connect(helper, &KAuth::HelperProxy::actionPerformed, this, [this](const QString &action, const ActionReply &reply) { 0053 d->actionPerformedSlot(action, reply); 0054 }); 0055 connect(helper, &KAuth::HelperProxy::progressStep, this, [this](const QString &action, int i) { 0056 d->progressStepSlot(action, i); 0057 }); 0058 connect(helper, &KAuth::HelperProxy::progressStepData, this, [this](const QString &action, const QVariantMap &data) { 0059 d->progressStepSlot(action, data); 0060 }); 0061 0062 connect(BackendsManager::authBackend(), &KAuth::AuthBackend::actionStatusChanged, this, [this](const QString &action, Action::AuthStatus status) { 0063 d->statusChangedSlot(action, status); 0064 }); 0065 } 0066 0067 ExecuteJob::~ExecuteJob() = default; 0068 0069 Action ExecuteJob::action() const 0070 { 0071 return d->action; 0072 } 0073 0074 QVariantMap ExecuteJob::data() const 0075 { 0076 return d->data; 0077 } 0078 0079 void ExecuteJob::start() 0080 { 0081 if (!d->action.isValid()) { 0082 qCWarning(KAUTH) << "Tried to start an invalid action: " << d->action.name(); 0083 ActionReply reply(ActionReply::InvalidActionError); 0084 reply.setErrorDescription(tr("Tried to start an invalid action")); 0085 d->actionPerformedSlot(d->action.name(), reply); 0086 return; 0087 } 0088 0089 switch (d->mode) { 0090 case Action::ExecuteMode: 0091 QTimer::singleShot(0, this, [this]() { 0092 d->doExecuteAction(); 0093 }); 0094 break; 0095 case Action::AuthorizeOnlyMode: 0096 QTimer::singleShot(0, this, [this]() { 0097 d->doAuthorizeAction(); 0098 }); 0099 break; 0100 default: { 0101 ActionReply reply(ActionReply::InvalidActionError); 0102 reply.setErrorDescription(tr("Unknown execution mode chosen")); 0103 d->actionPerformedSlot(d->action.name(), reply); 0104 break; 0105 } 0106 } 0107 } 0108 0109 bool ExecuteJob::kill(KillVerbosity verbosity) 0110 { 0111 BackendsManager::helperProxy()->stopAction(d->action.name(), d->action.helperId()); 0112 KJob::kill(verbosity); 0113 return true; 0114 } 0115 0116 void ExecuteJobPrivate::doExecuteAction() 0117 { 0118 // If this action authorizes from the client, let's do it now 0119 if (BackendsManager::authBackend()->capabilities() & KAuth::AuthBackend::AuthorizeFromClientCapability) { 0120 if (BackendsManager::authBackend()->capabilities() & KAuth::AuthBackend::PreAuthActionCapability) { 0121 BackendsManager::authBackend()->preAuthAction(action.name(), action.parentWindow()); 0122 } 0123 0124 Action::AuthStatus s = BackendsManager::authBackend()->authorizeAction(action.name()); 0125 0126 if (s == Action::AuthorizedStatus) { 0127 if (action.hasHelper()) { 0128 BackendsManager::helperProxy()->executeAction(action.name(), action.helperId(), action.detailsV2(), action.arguments(), action.timeout()); 0129 } else { 0130 // Done 0131 actionPerformedSlot(action.name(), ActionReply::SuccessReply()); 0132 } 0133 } else { 0134 // Abort if authorization fails 0135 switch (s) { 0136 case Action::DeniedStatus: 0137 actionPerformedSlot(action.name(), ActionReply::AuthorizationDeniedReply()); 0138 break; 0139 case Action::InvalidStatus: 0140 actionPerformedSlot(action.name(), ActionReply::InvalidActionReply()); 0141 break; 0142 case Action::UserCancelledStatus: 0143 actionPerformedSlot(action.name(), ActionReply::UserCancelledReply()); 0144 break; 0145 default: { 0146 ActionReply r(ActionReply::BackendError); 0147 r.setErrorDescription(tr("Unknown status for the authentication procedure")); 0148 actionPerformedSlot(action.name(), r); 0149 break; 0150 } 0151 } 0152 } 0153 } else if (BackendsManager::authBackend()->capabilities() & KAuth::AuthBackend::AuthorizeFromHelperCapability) { 0154 if (BackendsManager::authBackend()->capabilities() & KAuth::AuthBackend::PreAuthActionCapability) { 0155 BackendsManager::authBackend()->preAuthAction(action.name(), action.parentWindow()); 0156 } 0157 if (!action.hasHelper()) { 0158 ActionReply r(ActionReply::InvalidActionReply()); 0159 r.setErrorDescription(tr("The current backend only allows helper authorization, but this action does not have a helper.")); 0160 actionPerformedSlot(action.name(), r); 0161 return; 0162 } 0163 BackendsManager::helperProxy()->executeAction(action.name(), action.helperId(), action.detailsV2(), action.arguments(), action.timeout()); 0164 } else { 0165 // There's something totally wrong here 0166 ActionReply r(ActionReply::BackendError); 0167 r.setErrorDescription(tr("The backend does not specify how to authorize")); 0168 actionPerformedSlot(action.name(), r); 0169 } 0170 } 0171 0172 void ExecuteJobPrivate::doAuthorizeAction() 0173 { 0174 // Check the status first 0175 Action::AuthStatus s = action.status(); 0176 if (s == Action::AuthRequiredStatus) { 0177 // Let's check what to do 0178 if (BackendsManager::authBackend()->capabilities() & KAuth::AuthBackend::AuthorizeFromClientCapability) { 0179 // In this case we can actually try an authorization 0180 if (BackendsManager::authBackend()->capabilities() & KAuth::AuthBackend::PreAuthActionCapability) { 0181 BackendsManager::authBackend()->preAuthAction(action.name(), action.parentWindow()); 0182 } 0183 0184 s = BackendsManager::authBackend()->authorizeAction(action.name()); 0185 } else if (BackendsManager::authBackend()->capabilities() & KAuth::AuthBackend::AuthorizeFromHelperCapability) { 0186 // In this case, just throw out success, as the auth will take place later 0187 s = Action::AuthorizedStatus; 0188 } else { 0189 // This should never, never happen 0190 ActionReply r(ActionReply::BackendError); 0191 r.setErrorDescription(tr("The backend does not specify how to authorize")); 0192 actionPerformedSlot(action.name(), r); 0193 } 0194 } 0195 0196 // Return based on the current status 0197 if (s == Action::AuthorizedStatus) { 0198 actionPerformedSlot(action.name(), ActionReply::SuccessReply()); 0199 } else { 0200 actionPerformedSlot(action.name(), ActionReply::AuthorizationDeniedReply()); 0201 } 0202 } 0203 0204 void ExecuteJobPrivate::actionPerformedSlot(const QString &taction, const ActionReply &reply) 0205 { 0206 if (taction == action.name()) { 0207 if (reply.failed()) { 0208 q->setError(reply.errorCode()); 0209 q->setErrorText(reply.errorDescription()); 0210 } else { 0211 data = reply.data(); 0212 } 0213 0214 q->emitResult(); 0215 } 0216 } 0217 0218 void ExecuteJobPrivate::progressStepSlot(const QString &taction, int i) 0219 { 0220 if (taction == action.name()) { 0221 q->setPercent(i); 0222 } 0223 } 0224 0225 void ExecuteJobPrivate::progressStepSlot(const QString &taction, const QVariantMap &data) 0226 { 0227 if (taction == action.name()) { 0228 Q_EMIT q->newData(data); 0229 } 0230 } 0231 0232 void ExecuteJobPrivate::statusChangedSlot(const QString &taction, Action::AuthStatus status) 0233 { 0234 if (taction == action.name()) { 0235 Q_EMIT q->statusChanged(status); 0236 } 0237 } 0238 0239 } // namespace Auth 0240 0241 #include "moc_executejob.cpp"