on xenial help sign in
Allow logging into a desktop or tablet session again, by properly dismissing old PAM conversations. (LP: #1350878)

In a desktop or tablet, we were accidentally starting two PAM conversations in sequence on startup. Which is a small bug; it shouldn't normally be a problem, since each new PAM conversation should kill the old one. But the way we were killing the old one was subject to a thread race condition. See, a PAM conversation thread won't exit until all its prompts are answered. And what we do when we kill a PAM conversation is to answer all prompts with empty strings. But it's possible that when we want to kill a PAM conversation that it hasn't actually gotten to the point of prompting us yet. And when those prompts do come through, we were treating them as prompts for the new PAM conversation. So I've changed the PAM conversation logic to include a pam_handle and compare the handle with the current handle when being prompted. If it's an old handle, we just dismiss the prompt with an empty string response. Oh, and I fixed the bug that caused two prompts on startup in the first place. (But we still need the above logic anyway, for when you switch users quickly.) Fixes: 1350878 Approved by: Michał Sawicz, Stephen M. Webb, PS Jenkins bot

commitf35c4e8a6a4759d5b8edc3d4ccd163dd955ebe39 authorMichael Terry <michael.terry@canonical.com> dateFri 22 Aug 2014, 09:28 (12 years ago) parent2756c139c147d2
2 files changed+42−14
qml/Greeter/GreeterContent.qml−1 tests/mocks/LightDM/demo/GreeterPrivate.cpp+42−13
qml/Greeter/GreeterContent.qml−1
@@ -87,7 +87,6 @@ Item {
8787
8888 onLoaded: {
8989 item.currentIndex = greeterContentLoader.currentIndex;
90− item.resetAuthentication();
9190 }
9291
9392 Binding {
tests/mocks/LightDM/demo/GreeterPrivate.cpp+42−13
@@ -33,6 +33,12 @@ class GreeterImpl : public QObject
3333{
3434 Q_OBJECT
3535
36+ struct AppData
37+ {
38+ GreeterImpl *impl;
39+ pam_handle *handle;
40+ };
41+
3642 typedef QFutureInterface<QString> ResponseFuture;
3743
3844public:
@@ -46,11 +52,11 @@ public:
4652
4753 connect(&futureWatcher, SIGNAL(finished()),
4854 this, SLOT(finishPam()));
49− connect(this, SIGNAL(showMessage(QString, QLightDM::Greeter::MessageType)),
50− greeter, SIGNAL(showMessage(QString, QLightDM::Greeter::MessageType)));
55+ connect(this, SIGNAL(showMessage(pam_handle *, QString, QLightDM::Greeter::MessageType)),
56+ this, SLOT(handleMessage(pam_handle *, QString, QLightDM::Greeter::MessageType)));
5157 // This next connect is how we pass ResponseFutures between threads
52− connect(this, SIGNAL(showPrompt(QString, QLightDM::Greeter::PromptType, QLightDM::GreeterImpl::ResponseFuture)),
53− this, SLOT(handlePrompt(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)));
5460 }
5561
5662 void start(QString username)
@@ -64,14 +70,19 @@ public:
6470 pam_end(handle, PAM_CONV_ERR);
6571 }
6672
73+ AppData *appData = new AppData();
74+ appData->impl = this;
75+
6776 // Now actually start a new conversation with PAM
6877 pam_conv conversation;
6978 conversation.conv = converseWithPam;
70− conversation.appdata_ptr = static_cast<void*>(this);
79+ conversation.appdata_ptr = static_cast<void*>(appData);
7180
7281 if (pam_start("lightdm", username.toUtf8(), &conversation, &pamHandle) == PAM_SUCCESS) {
82+ appData->handle = pamHandle;
7383 futureWatcher.setFuture(QtConcurrent::run(authenticateWithPam, pamHandle));
7484 } else {
85+ delete appData;
7586 greeterPrivate->authenticated = false;
7687 Q_EMIT greeter->showMessage("Internal error: could not start PAM authentication", QLightDM::Greeter::MessageTypeError);
7788 Q_EMIT greeter->authenticationComplete();
@@ -103,7 +114,9 @@ public:
103114 if (!tmp_response)
104115 return PAM_CONV_ERR;
105116
106− GreeterImpl* impl = static_cast<GreeterImpl*>(appdata_ptr);
117+ AppData *appData = static_cast<AppData*>(appdata_ptr);
118+ GreeterImpl *impl = appData->impl;
119+ pam_handle *handle = appData->handle;
107120
108121 int count;
109122 QVector<ResponseFuture> responses;
@@ -117,7 +130,7 @@ public:
117130 QString message(msg[count]->msg);
118131 responses.append(ResponseFuture());
119132 responses.last().reportStarted();
120− Q_EMIT impl->showPrompt(message, Greeter::PromptTypeQuestion, responses.last());
133+ Q_EMIT impl->showPrompt(handle, message, Greeter::PromptTypeQuestion, responses.last());
121134 break;
122135 }
123136 case PAM_PROMPT_ECHO_OFF:
@@ -125,19 +138,19 @@ public:
125138 QString message(msg[count]->msg);
126139 responses.append(ResponseFuture());
127140 responses.last().reportStarted();
128− Q_EMIT impl->showPrompt(message, Greeter::PromptTypeSecret, responses.last());
141+ Q_EMIT impl->showPrompt(handle, message, Greeter::PromptTypeSecret, responses.last());
129142 break;
130143 }
131144 case PAM_TEXT_INFO:
132145 {
133146 QString message(msg[count]->msg);
134− Q_EMIT impl->showMessage(message, Greeter::MessageTypeInfo);
147+ Q_EMIT impl->showMessage(handle, message, Greeter::MessageTypeInfo);
135148 break;
136149 }
137150 default:
138151 {
139152 QString message(msg[count]->msg);
140− Q_EMIT impl->showMessage(message, Greeter::MessageTypeError);
153+ Q_EMIT impl->showMessage(handle, message, Greeter::MessageTypeError);
141154 break;
142155 }
143156 }
@@ -159,6 +172,8 @@ public:
159172 }
160173 }
161174
175+ delete appData;
176+
162177 if (raise_error)
163178 {
164179 for (int i = 0; i < count; ++i)
@@ -186,8 +201,8 @@ public Q_SLOTS:
186201 }
187202
188203Q_SIGNALS:
189− void showMessage(QString text, QLightDM::Greeter::MessageType type);
190− void showPrompt(QString text, QLightDM::Greeter::PromptType type, QLightDM::GreeterImpl::ResponseFuture response);
204+ void showMessage(pam_handle *handle, QString text, QLightDM::Greeter::MessageType type);
205+ void showPrompt(pam_handle *handle, QString text, QLightDM::Greeter::PromptType type, QLightDM::GreeterImpl::ResponseFuture response);
191206
192207private Q_SLOTS:
193208 void finishPam()
@@ -205,8 +220,22 @@ private Q_SLOTS:
205220 Q_EMIT greeter->authenticationComplete();
206221 }
207222
208− void handlePrompt(QString text, QLightDM::Greeter::PromptType type, QLightDM::GreeterImpl::ResponseFuture future)
223+ void handleMessage(pam_handle *handle, QString text, QLightDM::Greeter::MessageType type)
224+ {
225+ if (handle != pamHandle)
226+ return;
227+
228+ Q_EMIT greeter->showMessage(text, type);
229+ }
230+
231+ void handlePrompt(pam_handle *handle, QString text, QLightDM::Greeter::PromptType type, QLightDM::GreeterImpl::ResponseFuture future)
209232 {
233+ if (handle != pamHandle) {
234+ future.reportResult(QString());
235+ future.reportFinished();
236+ return;
237+ }
238+
210239 futures.enqueue(future);
211240 Q_EMIT greeter->showPrompt(text, type);
212241 }