[plasma/kscreenlocker] /: repair pamtest

Harald Sitter <[email protected]>
Newsgroups gmane.comp.kde.cvs
Message-ID <[email protected]>
Git commit d3c857b5792ffea071720e164ea8c3d231b8a787 by Harald Sitter.
Committed on 18/08/2026 at 11:15.
Pushed by sitter into branch 'master'.

repair pamtest

bit of a mixed bag

- we now *require* pam_wrapper inside the test scope
- pam_wrapper 1.1.6 is now necessary so we can run it on CI as well and
don't need UID_WRAPPER_DISABLE_DEEPBIND
- environment variables on the test get no longer thrashed
- environment variables on the test are now managed as a list variable
  for ease of reading and the ability to comment on stuff
- do not configure test_service in the wrong dir
- use different dirs for services and data so we can QFINDTESTDATA them
- wait for ready signal from authenticator (previously authenticators
were always ready. now they are not)
- disable the auth time checking to prevent pam_matrix from triggering
them by being too quick to authenticate

M  +15   -16   autotests/CMakeLists.txt
M  +7    -1    autotests/pamtest.cpp
M  +4    -0    greeter/pamauthenticator.cpp
M  +3    -0    greeter/pamauthenticator.h
M  +3    -1    greeter/worker/main.cpp

https://invent.kde.org/plasma/kscreenlocker/-/commit/d3c857b5792ffea071720e164ea8c3d231b8a787

diff --git a/autotests/CMakeLists.txt b/autotests/CMakeLists.txt
index 8bde2c0e..d7138eef 100644
--- a/autotests/CMakeLists.txt
+++ b/autotests/CMakeLists.txt
@@ -19,19 +19,18 @@ ecm_mark_as_test(logindTest)
 # PamTest
 #######################################
 
-pkg_search_module(PamWrapper pam_wrapper)
-# We're turning it off on the CI until pam_wrapper 1.15 is available on our image (which adds sanitizer support.)
-# see https://invent.kde.org/plasma/kscreenlocker/-/issues/11 for more details
-if (PamWrapper_FOUND AND NOT "$ENV{KDECI_BUILD}" STREQUAL "TRUE")
-    pkg_get_variable(PamWrapperModuleDir pam_wrapper "modules")
-    configure_file(data/test_service.in ./test_service)
-    add_executable(pamTest pamtest.cpp)
-    target_link_libraries(pamTest Qt::Test kscreenlocker_authenticator)
-    add_test(NAME ksmserver-pamTest COMMAND pamTest)
-    # they made a mistake in the env name, so set both old and new
-    set_tests_properties(ksmserver-pamTest PROPERTIES ENVIRONMENT "UID_WRAPPER_DISABLE_DEEPBIND=1;PAM_WRAPPER_DISABLE_DEEPBIND=1")
-    ecm_mark_as_test(pamTest)
-    set_property(TEST ksmserver-pamTest
-            PROPERTY
-            ENVIRONMENT "LD_PRELOAD=libpam_wrapper.so;ASAN_OPTIONS=verify_asan_link_order=0")
-endif()
+pkg_search_module(PamWrapper REQUIRED pam_wrapper>=1.1.6)
+pkg_get_variable(PamWrapperModuleDir pam_wrapper "modules")
+# We use a different target dir so we can QFINDTESTDATA the two dirs separately
+configure_file(data/test_service.in services/test_service)
+add_executable(pamTest pamtest.cpp)
+target_link_libraries(pamTest Qt::Test kscreenlocker_authenticator)
+add_test(NAME ksmserver-pamTest COMMAND pamTest)
+set(ksmserver-pamTest-environment
+    # We need to disable deepbind for pam_wrapper to work with ASAN
+    "PAM_WRAPPER_DISABLE_DEEPBIND=1"
+    "LD_PRELOAD=libpam_wrapper.so"
+    "ASAN_OPTIONS=verify_asan_link_order=0"
+)
+set_tests_properties(ksmserver-pamTest PROPERTIES ENVIRONMENT "${ksmserver-pamTest-environment}")
+ecm_mark_as_test(pamTest)
diff --git a/autotests/pamtest.cpp b/autotests/pamtest.cpp
index eb84df65..a3f7cc11 100644
--- a/autotests/pamtest.cpp
+++ b/autotests/pamtest.cpp
@@ -29,19 +29,25 @@ PamTest::PamTest()
 
     qputenv("PAM_WRAPPER", "1");
     qputenv("PAM_WRAPPER_DEBUGLEVEL", "2"); // DEBUG level
-    qputenv("PAM_WRAPPER_SERVICE_DIR", QFINDTESTDATA("data").toUtf8());
+    qputenv("PAM_WRAPPER_SERVICE_DIR", QFINDTESTDATA("services").toUtf8());
     qputenv("PAM_MATRIX_PASSWD", QFINDTESTDATA("data/test_db").toUtf8());
+
+    // Do not trigger the time checks. pam_matrix will respond way too quickly (expectedly)!
+    qputenv("KSCREENLOCKER_PAM_TIME_CHECK", "0");
 }
 
 void PamTest::testLogin()
 {
     PamAuthenticator auth(QStringLiteral("test_service"), QStringLiteral("test_user"));
+    QSignalSpy readySpy(&auth, &PamAuthenticator::readyChanged);
     QSignalSpy promptSpy(&auth, &PamAuthenticator::prompt);
     QSignalSpy promptForSecretSpy(&auth, &PamAuthenticator::promptForSecret);
     QSignalSpy succeededSpy(&auth, &PamAuthenticator::succeeded);
     QSignalSpy failedSpy(&auth, &PamAuthenticator::failed);
     QSignalSpy busyChangedSpy(&auth, &PamAuthenticator::busyChanged);
 
+    QVERIFY(readySpy.wait());
+
     // invalid password
     auth.tryUnlock();
 
diff --git a/greeter/pamauthenticator.cpp b/greeter/pamauthenticator.cpp
index b343b87a..07ab8f88 100644
--- a/greeter/pamauthenticator.cpp
+++ b/greeter/pamauthenticator.cpp
@@ -219,6 +219,10 @@ void PamAuthenticator::Ping(const QString &message)
         watcher->deleteLater();
         Q_ASSERT(watcher->isValid());
     });
+
+    Q_ASSERT(!m_ready); // only one ping ever. thank you!
+    m_ready = true;
+    Q_EMIT readyChanged();
 }
 
 QString PamAuthenticator::Prompt(const QString &msg)
diff --git a/greeter/pamauthenticator.h b/greeter/pamauthenticator.h
index a9c0de5e..d70064c4 100644
--- a/greeter/pamauthenticator.h
+++ b/greeter/pamauthenticator.h
@@ -25,6 +25,7 @@ class PamAuthenticator : public QObject, protected QDBusContext
     QML_NAMED_ELEMENT(Authenticator)
     QML_UNCREATABLE("Not exposed except for its enum")
 
+    Q_PROPERTY(bool ready MEMBER m_ready NOTIFY readyChanged)
     Q_PROPERTY(bool busy READ isBusy NOTIFY busyChanged)
     Q_PROPERTY(bool inPasswordDelay READ inPasswordDelay NOTIFY inPasswordDelayChanged)
     Q_PROPERTY(bool available READ isAvailable NOTIFY availableChanged)
@@ -92,6 +93,7 @@ public:
     void setInPasswordDelay(bool timeout);
 
 Q_SIGNALS:
+    void readyChanged();
     void busyChanged();
     void promptForSecret(const QString &msg);
     void prompt(const QString &msg);
@@ -128,6 +130,7 @@ private:
     QString m_errorMessage;
     QString m_infoMessage;
     QString m_service;
+    bool m_ready = false;
     bool m_busy = false;
     bool m_unlocked = false;
     bool m_unavailable = false;
diff --git a/greeter/worker/main.cpp b/greeter/worker/main.cpp
index b0685d94..0ccd0ace 100644
--- a/greeter/worker/main.cpp
+++ b/greeter/worker/main.cpp
@@ -246,8 +246,10 @@ WorkerResult::Type Worker::authenticate()
 
     qCWarning(WORKER) << timer.elapsed() << "ms elapsed during pam_authenticate call for service" << qUtf8Printable(m_service) << "with result code" << rc;
 
+    constexpr auto checkTimesDefault = "1"_L1;
+    static const auto checkTimes = qEnvironmentVariable("KSCREENLOCKER_PAM_TIME_CHECK", checkTimesDefault) == checkTimesDefault;
     constexpr auto tooQuick = 50ms;
-    if (timer.durationElapsed() <= tooQuick) {
+    if (checkTimes && timer.durationElapsed() <= tooQuick) {
         // This happened faster than is reasonable for any service -> let's mark as unavailable to avoid hammering a broken service with retries
         // Has been observed with the vibe coded face authenticators on github. They will report success in 0ms when they are totally defunct.
         qCWarning(WORKER) << "Unexpectedly short auth error on PAM service" << qUtf8Printable(m_service) << timer.durationElapsed();
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.