File indexing completed on 2024-05-05 05:30:28
0001 /* 0002 SPDX-FileCopyrightText: 2023 Janet Blackquill <uhhadd@gmail.com> 0003 0004 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0005 */ 0006 0007 #include <QDebug> 0008 #include <algorithm> 0009 0010 #include "kscreenlocker_greet_logging.h" 0011 #include "pamauthenticator.h" 0012 #include "pamauthenticators.h" 0013 0014 struct PamAuthenticators::Private { 0015 std::unique_ptr<PamAuthenticator> interactive; 0016 std::vector<std::unique_ptr<PamAuthenticator>> noninteractive; 0017 PamAuthenticator::NoninteractiveAuthenticatorTypes computedTypes = PamAuthenticator::NoninteractiveAuthenticatorType::None; 0018 AuthenticatorsState state = AuthenticatorsState::Idle; 0019 0020 void recomputeNoninteractiveAuthenticationTypes() 0021 { 0022 PamAuthenticator::NoninteractiveAuthenticatorTypes result = PamAuthenticator::NoninteractiveAuthenticatorType::None; 0023 for (auto &&noninteractive : noninteractive) { 0024 if (noninteractive->isAvailable()) { 0025 result |= noninteractive->authenticatorType(); 0026 } 0027 } 0028 computedTypes = result; 0029 } 0030 void cancelNoninteractive() 0031 { 0032 for (auto &&noninteractive : noninteractive) { 0033 noninteractive->cancel(); 0034 } 0035 } 0036 }; 0037 0038 PamAuthenticators::PamAuthenticators(std::unique_ptr<PamAuthenticator> &&interactive, 0039 std::vector<std::unique_ptr<PamAuthenticator>> &&noninteractive, 0040 QObject *parent) 0041 : QObject(parent) 0042 , d(new Private{std::move(interactive), std::move(noninteractive)}) 0043 { 0044 connect(d->interactive.get(), &PamAuthenticator::succeeded, this, [this] { 0045 qCDebug(KSCREENLOCKER_GREET) << "PamAuthenticators: Success from interactive authenticator" << qUtf8Printable(d->interactive->service()); 0046 Q_EMIT succeeded(); 0047 }); 0048 connect(d->interactive.get(), &PamAuthenticator::failed, this, [this] { 0049 qCDebug(KSCREENLOCKER_GREET) << "PamAuthenticators: Failure from interactive authenticator" << qUtf8Printable(d->interactive->service()); 0050 setState(AuthenticatorsState::Idle); 0051 d->cancelNoninteractive(); 0052 Q_EMIT failed(PamAuthenticator::NoninteractiveAuthenticatorType::None, d->interactive.get()); 0053 }); 0054 for (auto &&noninteractive : d->noninteractive) { 0055 connect(noninteractive.get(), &PamAuthenticator::succeeded, this, [this, &noninteractive] { 0056 qCDebug(KSCREENLOCKER_GREET) << "PamAuthenticators: Success from non-interactive authenticator" << qUtf8Printable(noninteractive->service()); 0057 Q_EMIT succeeded(); 0058 }); 0059 connect(noninteractive.get(), &PamAuthenticator::availableChanged, this, [this, &noninteractive] { 0060 qCDebug(KSCREENLOCKER_GREET) << "PamAuthenticators: Availability changed for non-interactive authenticator" 0061 << qUtf8Printable(noninteractive->service()) << noninteractive->isAvailable(); 0062 d->recomputeNoninteractiveAuthenticationTypes(); 0063 Q_EMIT authenticatorTypesChanged(); 0064 }); 0065 connect(noninteractive.get(), &PamAuthenticator::failed, this, [this, &noninteractive] { 0066 qCDebug(KSCREENLOCKER_GREET) << "PamAuthenticators: Non-interactive authenticator" << qUtf8Printable(noninteractive->service()) << "failed"; 0067 Q_EMIT failed(noninteractive->authenticatorType(), noninteractive.get()); 0068 }); 0069 connect(noninteractive.get(), &PamAuthenticator::infoMessage, this, [this, &noninteractive]() { 0070 qCDebug(KSCREENLOCKER_GREET) << "PamAuthenticators: Info message from non-interactive authenticator" << qUtf8Printable(noninteractive->service()); 0071 Q_EMIT noninteractiveInfo(noninteractive->authenticatorType(), noninteractive.get()); 0072 }); 0073 connect(noninteractive.get(), &PamAuthenticator::errorMessage, this, [this, &noninteractive]() { 0074 qCDebug(KSCREENLOCKER_GREET) << "PamAuthenticators: Error message from non-interactive authenticator " << qUtf8Printable(noninteractive->service()); 0075 Q_EMIT noninteractiveError(noninteractive->authenticatorType(), noninteractive.get()); 0076 }); 0077 } 0078 0079 // connect the delegated signals 0080 connect(d->interactive.get(), &PamAuthenticator::busyChanged, this, [this] { 0081 qCDebug(KSCREENLOCKER_GREET) << "PamAuthenticators: Interactive authenticator" << qUtf8Printable(d->interactive->service()) << "changed business"; 0082 Q_EMIT busyChanged(); 0083 }); 0084 connect(d->interactive.get(), &PamAuthenticator::prompt, this, [this] { 0085 qCDebug(KSCREENLOCKER_GREET) << "PamAuthenticators: Normal prompt from interactive authenticator" << qUtf8Printable(d->interactive->service()); 0086 Q_EMIT promptChanged(); 0087 }); 0088 connect(d->interactive.get(), &PamAuthenticator::promptForSecret, this, [this] { 0089 qCDebug(KSCREENLOCKER_GREET) << "PamAuthenticators: Secret prompt from interactive authenticator" << qUtf8Printable(d->interactive->service()); 0090 Q_EMIT promptForSecretChanged(); 0091 }); 0092 connect(d->interactive.get(), &PamAuthenticator::infoMessage, this, [this] { 0093 qCDebug(KSCREENLOCKER_GREET) << "PamAuthenticators: Info message from interactive authenticator" << qUtf8Printable(d->interactive->service()); 0094 Q_EMIT infoMessageChanged(); 0095 }); 0096 connect(d->interactive.get(), &PamAuthenticator::errorMessage, this, [this] { 0097 qCDebug(KSCREENLOCKER_GREET) << "PamAuthenticators: Error message from interactive authenticator" << qUtf8Printable(d->interactive->service()); 0098 Q_EMIT errorMessageChanged(); 0099 }); 0100 } 0101 0102 PamAuthenticators::~PamAuthenticators() 0103 { 0104 } 0105 0106 bool PamAuthenticators::isUnlocked() const 0107 { 0108 return d->interactive->isUnlocked() || std::any_of(d->noninteractive.cbegin(), d->noninteractive.cend(), [](auto &&t) { 0109 return t->isUnlocked(); 0110 }); 0111 } 0112 0113 PamAuthenticators::AuthenticatorsState PamAuthenticators::state() const 0114 { 0115 return d->state; 0116 } 0117 0118 void PamAuthenticators::startAuthenticating() 0119 { 0120 if (d->state == AuthenticatorsState::Authenticating) { 0121 return; 0122 } 0123 0124 qCDebug(KSCREENLOCKER_GREET) << "PamAuthenticators: starting authenticators"; 0125 d->interactive->tryUnlock(); 0126 for (auto &&noninteractive : d->noninteractive) { 0127 noninteractive->tryUnlock(); 0128 } 0129 setState(AuthenticatorsState::Authenticating); 0130 } 0131 0132 void PamAuthenticators::stopAuthenticating() 0133 { 0134 qCDebug(KSCREENLOCKER_GREET) << "PamAuthenticators: stopping authenticators"; 0135 for (auto &&noninteractive : d->noninteractive) { 0136 noninteractive->cancel(); 0137 } 0138 d->interactive->cancel(); 0139 setState(AuthenticatorsState::Idle); 0140 } 0141 0142 void PamAuthenticators::setState(AuthenticatorsState state) 0143 { 0144 if (d->state == state) { 0145 return; 0146 } 0147 qCDebug(KSCREENLOCKER_GREET) << "PamAuthenticators: state changing from" << d->state << "to" << state; 0148 d->state = state; 0149 Q_EMIT stateChanged(); 0150 } 0151 0152 // these properties are delegated to interactive authenticator 0153 0154 bool PamAuthenticators::isBusy() const 0155 { 0156 return d->interactive->isBusy(); 0157 } 0158 0159 QString PamAuthenticators::prompt() const 0160 { 0161 return d->interactive->getPrompt(); 0162 } 0163 0164 QString PamAuthenticators::promptForSecret() const 0165 { 0166 return d->interactive->getPromptForSecret(); 0167 } 0168 0169 QString PamAuthenticators::infoMessage() const 0170 { 0171 return d->interactive->getInfoMessage(); 0172 } 0173 0174 QString PamAuthenticators::errorMessage() const 0175 { 0176 return d->interactive->getErrorMessage(); 0177 } 0178 0179 void PamAuthenticators::respond(const QByteArray &response) 0180 { 0181 qCDebug(KSCREENLOCKER_GREET) << "PamAuthenticators: responding to interactive authenticator"; 0182 return d->interactive->respond(response); 0183 } 0184 0185 void PamAuthenticators::cancel() 0186 { 0187 qCDebug(KSCREENLOCKER_GREET) << "PamAuthenticators: cancelling interactive authenticator"; 0188 return d->interactive->cancel(); 0189 } 0190 0191 PamAuthenticator::NoninteractiveAuthenticatorTypes PamAuthenticators::authenticatorTypes() const 0192 { 0193 return d->computedTypes; 0194 }