on xenial help sign in
Be more emphatic about cancelling a PAM thread
aeb0898Michael Terry
plugins/LightDM/liblightdm/GreeterPrivate.cpp+14−5
@@ -56,7 +56,8 @@ public:
56 this, SLOT(handleMessage(pam_handle *, QString, QLightDM::Greeter::MessageType)));
56 this, SLOT(handleMessage(pam_handle *, QString, QLightDM::Greeter::MessageType)));
57 // This next connect is how we pass ResponseFutures between threads
57 // This next connect is how we pass ResponseFutures between threads
58 connect(this, SIGNAL(showPrompt(pam_handle *, QString, QLightDM::Greeter::PromptType, QLightDM::GreeterImpl::ResponseFuture)),
58 connect(this, SIGNAL(showPrompt(pam_handle *, QString, QLightDM::Greeter::PromptType, QLightDM::GreeterImpl::ResponseFuture)),
59− this, SLOT(handlePrompt(pam_handle *, QString, QLightDM::Greeter::PromptType, QLightDM::GreeterImpl::ResponseFuture)));
59+ this, SLOT(handlePrompt(pam_handle *, QString, QLightDM::Greeter::PromptType, QLightDM::GreeterImpl::ResponseFuture)),
60+ Qt::BlockingQueuedConnection);
60 }
61 }
61
62
62 ~GreeterImpl()
63 ~GreeterImpl()
@@ -79,7 +80,7 @@ public:
79
80
80 if (pam_start("lightdm", username.toUtf8(), &conversation, &pamHandle) == PAM_SUCCESS) {
81 if (pam_start("lightdm", username.toUtf8(), &conversation, &pamHandle) == PAM_SUCCESS) {
81 appData->handle = pamHandle;
82 appData->handle = pamHandle;
82− futureWatcher.setFuture(QtConcurrent::run(authenticateWithPam, pamHandle));
83+ futureWatcher.setFuture(QtConcurrent::mapped(QList<pam_handle*>() << pamHandle, authenticateWithPam));
83 } else {
84 } else {
84 delete appData;
85 delete appData;
85 greeterPrivate->authenticated = false;
86 greeterPrivate->authenticated = false;
@@ -88,7 +89,7 @@ public:
88 }
89 }
89 }
90 }
90
91
91− static int authenticateWithPam(pam_handle* pamHandle)
92+ static int authenticateWithPam(pam_handle* const& pamHandle)
92 {
93 {
93 int pamStatus = pam_authenticate(pamHandle, 0);
94 int pamStatus = pam_authenticate(pamHandle, 0);
94 if (pamStatus == PAM_SUCCESS) {
95 if (pamStatus == PAM_SUCCESS) {
@@ -242,11 +243,14 @@ private Q_SLOTS:
242private:
243private:
243 void cancelPam()
244 void cancelPam()
244 {
245 {
245− // Unfortunately we can't simply cancel our QFuture because QtConcurrent::run doesn't support cancel
246 if (pamHandle != nullptr) {
246 if (pamHandle != nullptr) {
247 pam_handle *handle = pamHandle;
247 pam_handle *handle = pamHandle;
248 pamHandle = nullptr; // to disable normal finishPam() handling
248 pamHandle = nullptr; // to disable normal finishPam() handling
249+ futureWatcher.future().cancel();
250+ while (!futureWatcher.future().isFinished()) {
251+ QCoreApplication::processEvents(); // let signal/slot handling happen
249− while (respond(QString())); // clear our local queue of QFutures
252+ respond(QString());
253+ }
250 pam_end(handle, PAM_CONV_ERR);
254 pam_end(handle, PAM_CONV_ERR);
251 }
255 }
252 }
256 }
@@ -266,6 +270,11 @@ GreeterPrivate::GreeterPrivate(Greeter* parent)
266{
270{
267}
271}
268
272
273+GreeterPrivate::~GreeterPrivate()
274+{
275+ delete m_impl;
276+}
277+
269void GreeterPrivate::handleAuthenticate()
278void GreeterPrivate::handleAuthenticate()
270{
279{
271 m_impl->start(authenticationUser);
280 m_impl->start(authenticationUser);
plugins/LightDM/liblightdm/GreeterPrivate.h+1−1
@@ -30,7 +30,7 @@ class GreeterPrivate
30{
30{
31public:
31public:
32 explicit GreeterPrivate(Greeter* parent=0);
32 explicit GreeterPrivate(Greeter* parent=0);
33− virtual ~GreeterPrivate() = default;
33+ virtual ~GreeterPrivate();
34
34
35 // These variables may not be used by all subclasses, that's no problem
35 // These variables may not be used by all subclasses, that's no problem
36 bool authenticated;
36 bool authenticated;
tests/plugins/LightDM/CMakeLists.txt+35−18
@@ -1,35 +1,52 @@
1+add_definitions(
2+ -DCURRENT_SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}"
3+ )
4+include_directories(
5+ ${CMAKE_CURRENT_BINARY_DIR}
6+ )
7+
1add_executable(GreeterDBusTestExec
8add_executable(GreeterDBusTestExec
2 dbus.cpp
9 dbus.cpp
3 ${CMAKE_SOURCE_DIR}/plugins/LightDM/Greeter.cpp
10 ${CMAKE_SOURCE_DIR}/plugins/LightDM/Greeter.cpp
4 )
11 )
5qt5_use_modules(GreeterDBusTestExec Core DBus Quick Test)
12qt5_use_modules(GreeterDBusTestExec Core DBus Quick Test)
6−
13+target_link_libraries(GreeterDBusTestExec
7−add_executable(GreeterUsersModelTestExec
14+ -L${CMAKE_BINARY_DIR}/tests/mocks/LightDM/liblightdm
8− usersmodel.cpp
15+ -llightdm-qt5-2
9− ${CMAKE_SOURCE_DIR}/plugins/LightDM/UsersModel.cpp
10− ${CMAKE_SOURCE_DIR}/plugins/Utils/unitysortfilterproxymodelqml.cpp
11 )
16 )
12−qt5_use_modules(GreeterUsersModelTestExec Core Test)
17+target_include_directories(GreeterDBusTestExec PUBLIC
13−
14−include_directories(
15− ${CMAKE_CURRENT_BINARY_DIR}
16 ${CMAKE_SOURCE_DIR}/plugins/LightDM
18 ${CMAKE_SOURCE_DIR}/plugins/LightDM
17− ${CMAKE_SOURCE_DIR}/plugins/Utils
18 ${CMAKE_SOURCE_DIR}/tests/mocks/LightDM
19 ${CMAKE_SOURCE_DIR}/tests/mocks/LightDM
19 )
20 )
21+add_binary_qml_test(GreeterDBus "${CMAKE_BINARY_DIR}/tests/mocks/LightDM/liblightdm" MockLightDM "QML2_IMPORT_PATH=${CMAKE_BINARY_DIR}/tests/mocks")
20
22
23+add_executable(GreeterPamTestExec
24+ pam.cpp
25+ ${CMAKE_SOURCE_DIR}/plugins/LightDM/liblightdm/GreeterPrivate.cpp
26+ )
27+qt5_use_modules(GreeterPamTestExec Concurrent Core Test)
21−target_link_libraries(GreeterDBusTestExec
28+target_link_libraries(GreeterPamTestExec
29+ integratedLightDM
30+ )
31+target_include_directories(GreeterPamTestExec PUBLIC
22− -L${CMAKE_BINARY_DIR}/tests/mocks/LightDM/liblightdm
32+ ${CMAKE_SOURCE_DIR}/plugins/LightDM/liblightdm
23− -llightdm-qt5-2
24 )
33 )
34+add_qmltest_target(testGreeterPam "${CMAKE_CURRENT_BINARY_DIR}/GreeterPamTestExec" TRUE FALSE)
35+add_dependencies(testGreeterPam GreeterPamTestExec)
25
36
37+add_executable(GreeterUsersModelTestExec
38+ usersmodel.cpp
39+ ${CMAKE_SOURCE_DIR}/plugins/LightDM/UsersModel.cpp
40+ ${CMAKE_SOURCE_DIR}/plugins/Utils/unitysortfilterproxymodelqml.cpp
41+ )
42+qt5_use_modules(GreeterUsersModelTestExec Core Test)
26target_link_libraries(GreeterUsersModelTestExec
43target_link_libraries(GreeterUsersModelTestExec
27 -L${CMAKE_BINARY_DIR}/tests/mocks/LightDM/liblightdm
44 -L${CMAKE_BINARY_DIR}/tests/mocks/LightDM/liblightdm
28 -llightdm-qt5-2
45 -llightdm-qt5-2
29 )
46 )
30−
47+target_include_directories(GreeterUsersModelTestExec PUBLIC
31−add_definitions(-DCURRENT_SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}")
48+ ${CMAKE_SOURCE_DIR}/plugins/LightDM
32−
49+ ${CMAKE_SOURCE_DIR}/plugins/Utils
33−add_binary_qml_test(GreeterDBus "${CMAKE_BINARY_DIR}/tests/mocks/LightDM/liblightdm" MockLightDM "QML2_IMPORT_PATH=${CMAKE_BINARY_DIR}/tests/mocks")
50+ ${CMAKE_SOURCE_DIR}/tests/mocks/LightDM
34−
51+ )
35add_binary_qml_test(GreeterUsersModel "${CMAKE_BINARY_DIR}/tests/mocks/LightDM/liblightdm" MockLightDM "LIBLIGHTDM_MOCK_MODE=full")
52add_binary_qml_test(GreeterUsersModel "${CMAKE_BINARY_DIR}/tests/mocks/LightDM/liblightdm" MockLightDM "LIBLIGHTDM_MOCK_MODE=full")
tests/plugins/LightDM/pam.cppnew file+51
@@ -0,0 +1,51 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "GreeterPrivate.h"
18+
19+#include <QtTest>
20+
21+class GreeterPamTest : public QObject
22+{
23+ Q_OBJECT
24+
25+private Q_SLOTS:
26+
27+ void init()
28+ {
29+ m_greeterpriv = new QLightDM::GreeterPrivate();
30+ }
31+
32+ void cleanup()
33+ {
34+ delete m_greeterpriv;
35+ }
36+
37+ void testRapidFireAuthentication()
38+ {
39+ m_greeterpriv->authenticationUser = qgetenv("USER");
40+ for (int i = 0; i < 100; i++) {
41+ m_greeterpriv->handleAuthenticate();
42+ }
43+ }
44+
45+private:
46+ QLightDM::GreeterPrivate *m_greeterpriv;
47+};
48+
49+QTEST_MAIN(GreeterPamTest)
50+
51+#include "pam.moc"