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 }