25 #include <sys/types.h> 29 #include <QStringList> 30 #include <QThreadStorage> 32 #include <QDataStream> 35 #include "SignOn/uisessiondata_priv.h" 36 #include "SignOn/signonplugincommon.h" 43 #include "SignOn/authpluginif.h" 46 #include "SignOn/blobiohandler.h" 47 #include "SignOn/ipc.h" 51 #define REMOTEPLUGIN_BIN_PATH QLatin1String("signonpluginprocess") 52 #define PLUGINPROCESS_START_TIMEOUT 5000 53 #define PLUGINPROCESS_STOP_TIMEOUT 1000 61 PluginProcess::PluginProcess(QObject *parent):
66 PluginProcess::~PluginProcess()
72 PluginProxy::PluginProxy(QString type, QObject *parent):
78 m_isProcessing =
false;
79 m_isResultObtained =
false;
80 m_currentResultOperation = -1;
81 m_process =
new PluginProcess(
this);
84 if (criticalsEnabled()) {
85 const char *level = debugEnabled() ?
"2" :
"1";
86 QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
87 env.insert(QLatin1String(
"SSO_DEBUG"), QLatin1String(level));
88 m_process->setProcessEnvironment(env);
92 connect(m_process, SIGNAL(readyReadStandardError()),
93 this, SLOT(onReadStandardError()));
99 connect(m_process, SIGNAL(finished(
int, QProcess::ExitStatus)),
100 this, SLOT(onExit(
int, QProcess::ExitStatus)));
101 connect(m_process, SIGNAL(error(QProcess::ProcessError)),
102 this, SLOT(onError(QProcess::ProcessError)));
105 PluginProxy::~PluginProxy()
107 if (m_process != NULL &&
108 m_process->state() != QProcess::NotRunning)
118 m_process->closeWriteChannel();
121 qCritical() <<
"The signon plugin does not react on demand to " 122 "stop: need to kill it!!!";
127 if (m_process->pid()) {
128 qCritical() <<
"The signon plugin seems to ignore kill(), " 129 "killing it from command line";
130 QString killProcessCommand(QString::fromLatin1(
"kill -9 %1").arg(m_process->pid()));
131 QProcess::execute(killProcessCommand);
138 PluginProxy* PluginProxy::createNewPluginProxy(
const QString &type)
142 QStringList args = QStringList() << pp->m_type;
148 TRACE() <<
"The process cannot be started";
154 TRACE() <<
"The process cannot load plugin";
159 if (debugEnabled()) {
160 QString pluginType = pp->queryType();
161 if (pluginType != pp->m_type) {
162 BLAME() << QString::fromLatin1(
"Plugin returned type '%1', " 164 arg(pluginType).arg(pp->m_type);
167 pp->m_mechanisms = pp->queryMechanisms();
169 connect(pp->m_process, SIGNAL(readyRead()),
170 pp, SLOT(onReadStandardOutput()));
172 TRACE() <<
"The process is started";
177 const QString &mechanism)
179 if (!restartIfRequired())
182 m_isResultObtained =
false;
183 QVariant value = inData.value(SSOUI_KEY_UIPOLICY);
184 m_uiPolicy = value.toInt();
186 QDataStream in(m_process);
187 in << (quint32)PLUGIN_OP_PROCESS;
190 m_blobIOHandler->sendData(inData);
192 m_isProcessing =
true;
196 bool PluginProxy::processUi(
const QVariantMap &inData)
200 if (!restartIfRequired())
203 QDataStream in(m_process);
205 in << (quint32)PLUGIN_OP_PROCESS_UI;
207 m_blobIOHandler->sendData(inData);
209 m_isProcessing =
true;
214 bool PluginProxy::processRefresh(
const QVariantMap &inData)
218 if (!restartIfRequired())
221 QDataStream in(m_process);
223 in << (quint32)PLUGIN_OP_REFRESH;
225 m_blobIOHandler->sendData(inData);
227 m_isProcessing =
true;
232 void PluginProxy::cancel()
235 QDataStream in(m_process);
236 in << (quint32)PLUGIN_OP_CANCEL;
239 void PluginProxy::stop()
242 QDataStream in(m_process);
243 in << (quint32)PLUGIN_OP_STOP;
246 bool PluginProxy::readOnReady(QByteArray &buffer,
int timeout)
248 bool ready = m_process->waitForReadyRead(timeout);
251 if (!m_process->bytesAvailable())
254 while (m_process->bytesAvailable())
255 buffer += m_process->readAllStandardOutput();
261 bool PluginProxy::isProcessing()
263 return m_isProcessing;
266 void PluginProxy::blobIOError()
269 disconnect(m_blobIOHandler, SIGNAL(error()),
this, SLOT(blobIOError()));
272 connect(m_process, SIGNAL(readyRead()),
this, SLOT(onReadStandardOutput()));
274 (
int)Error::InternalServer,
275 QLatin1String(
"Failed to I/O session data to/from the authentication " 279 bool PluginProxy::isResultOperationCodeValid(
const int opCode)
const 281 if (opCode == PLUGIN_RESPONSE_RESULT
282 || opCode == PLUGIN_RESPONSE_STORE
283 || opCode == PLUGIN_RESPONSE_ERROR
284 || opCode == PLUGIN_RESPONSE_SIGNAL
285 || opCode == PLUGIN_RESPONSE_UI
286 || opCode == PLUGIN_RESPONSE_REFRESHED)
return true;
291 void PluginProxy::onReadStandardOutput()
293 disconnect(m_process, SIGNAL(readyRead()),
294 this, SLOT(onReadStandardOutput()));
296 if (!m_process->bytesAvailable()) {
297 qCritical() <<
"No information available on process";
298 m_isProcessing =
false;
299 emit processError(Error::InternalServer, QString());
303 QDataStream reader(m_process);
304 reader >> m_currentResultOperation;
306 TRACE() <<
"PROXY RESULT OPERATION:" << m_currentResultOperation;
308 if (!isResultOperationCodeValid(m_currentResultOperation)) {
309 TRACE() <<
"Unknown operation code - skipping.";
312 Q_UNUSED(m_process->readAllStandardOutput());
314 connect(m_process, SIGNAL(readyRead()),
315 this, SLOT(onReadStandardOutput()));
319 if (m_currentResultOperation != PLUGIN_RESPONSE_SIGNAL &&
320 m_currentResultOperation != PLUGIN_RESPONSE_ERROR) {
322 connect(m_blobIOHandler, SIGNAL(error()),
323 this, SLOT(blobIOError()));
325 int expectedDataSize = 0;
326 reader >> expectedDataSize;
327 TRACE() <<
"PROXY EXPECTED DATA SIZE:" << expectedDataSize;
329 m_blobIOHandler->receiveData(expectedDataSize);
331 handlePluginResponse(m_currentResultOperation);
335 void PluginProxy::sessionDataReceived(
const QVariantMap &map)
337 handlePluginResponse(m_currentResultOperation, map);
340 void PluginProxy::handlePluginResponse(
const quint32 resultOperation,
341 const QVariantMap &sessionDataMap)
343 TRACE() << resultOperation;
345 if (resultOperation == PLUGIN_RESPONSE_RESULT) {
346 TRACE() <<
"PLUGIN_RESPONSE_RESULT";
348 m_isProcessing =
false;
350 if (!m_isResultObtained)
351 emit processResultReply(sessionDataMap);
353 BLAME() <<
"Unexpected plugin response: ";
355 m_isResultObtained =
true;
356 }
else if (resultOperation == PLUGIN_RESPONSE_STORE) {
357 TRACE() <<
"PLUGIN_RESPONSE_STORE";
359 if (!m_isResultObtained)
360 emit processStore(sessionDataMap);
362 BLAME() <<
"Unexpected plugin store: ";
364 }
else if (resultOperation == PLUGIN_RESPONSE_UI) {
365 TRACE() <<
"PLUGIN_RESPONSE_UI";
367 if (!m_isResultObtained) {
370 if (m_uiPolicy == NoUserInteractionPolicy)
373 if (m_uiPolicy == ValidationPolicy) {
374 bool credentialsQueried =
375 (sessionDataMap.contains(SSOUI_KEY_QUERYUSERNAME)
376 || sessionDataMap.contains(SSOUI_KEY_QUERYPASSWORD));
378 bool captchaQueried =
379 (sessionDataMap.contains(SSOUI_KEY_CAPTCHAIMG)
380 || sessionDataMap.contains(SSOUI_KEY_CAPTCHAURL));
382 if (credentialsQueried && !captchaQueried)
388 TRACE() <<
"ui policy prevented ui launch";
390 QVariantMap nonConstMap = sessionDataMap;
391 nonConstMap.insert(SSOUI_KEY_ERROR, QUERY_ERROR_FORBIDDEN);
392 processUi(nonConstMap);
394 TRACE() <<
"open ui";
395 emit processUiRequest(sessionDataMap);
398 BLAME() <<
"Unexpected plugin ui response: ";
400 }
else if (resultOperation == PLUGIN_RESPONSE_REFRESHED) {
401 TRACE() <<
"PLUGIN_RESPONSE_REFRESHED";
403 if (!m_isResultObtained)
404 emit processRefreshRequest(sessionDataMap);
406 BLAME() <<
"Unexpected plugin ui response: ";
407 }
else if (resultOperation == PLUGIN_RESPONSE_ERROR) {
408 TRACE() <<
"PLUGIN_RESPONSE_ERROR";
410 QString errorMessage;
412 QDataStream stream(m_process);
414 stream >> errorMessage;
415 m_isProcessing =
false;
417 if (!m_isResultObtained)
418 emit processError((
int)err, errorMessage);
420 BLAME() <<
"Unexpected plugin error: " << errorMessage;
422 m_isResultObtained =
true;
423 }
else if (resultOperation == PLUGIN_RESPONSE_SIGNAL) {
424 TRACE() <<
"PLUGIN_RESPONSE_SIGNAL";
428 QDataStream stream(m_process);
432 if (!m_isResultObtained)
433 emit stateChanged((
int)state, message);
435 BLAME() <<
"Unexpected plugin signal: " << state << message;
438 connect(m_process, SIGNAL(readyRead()),
this, SLOT(onReadStandardOutput()));
439 if (m_process->bytesAvailable()) {
440 TRACE() <<
"plugin has more to read after handling a response";
441 onReadStandardOutput();
445 void PluginProxy::onReadStandardError()
447 QString ba = QString::fromLatin1(m_process->readAllStandardError());
450 void PluginProxy::onExit(
int exitCode, QProcess::ExitStatus exitStatus)
452 TRACE() <<
"Plugin process exit with code " << exitCode <<
455 if (m_isProcessing || exitStatus == QProcess::CrashExit) {
456 qCritical() <<
"Challenge produces CRASH!";
457 emit processError(Error::InternalServer,
458 QLatin1String(
"plugin processed crashed"));
461 TRACE() <<
"plugin process terminated because cannot change user";
464 m_isProcessing =
false;
467 void PluginProxy::onError(QProcess::ProcessError err)
469 TRACE() <<
"Error: " << err;
472 QString PluginProxy::queryType()
476 if (!restartIfRequired())
479 QDataStream ds(m_process);
480 ds << (quint32)PLUGIN_OP_TYPE;
486 qCritical(
"PluginProxy returned NULL result");
489 QDataStream out(buffer);
494 QStringList PluginProxy::queryMechanisms()
498 if (!restartIfRequired())
499 return QStringList();
501 QDataStream in(m_process);
502 in << (quint32)PLUGIN_OP_MECHANISMS;
510 QVariant mechanismsVar;
511 QDataStream out(buffer);
513 out >> mechanismsVar;
514 QVariantList varList = mechanismsVar.toList();
516 for (
int i = 0; i < varList.count(); i++)
517 strList << varList.at(i).toString();
521 qCritical(
"PluginProxy returned NULL result");
526 bool PluginProxy::waitForStarted(
int timeout)
528 if (!m_process->waitForStarted(timeout))
531 m_blobIOHandler =
new BlobIOHandler(m_process, m_process,
this);
533 connect(m_blobIOHandler,
534 SIGNAL(dataReceived(
const QVariantMap &)),
536 SLOT(sessionDataReceived(
const QVariantMap &)));
538 QSocketNotifier *readNotifier =
539 new QSocketNotifier(STDIN_FILENO, QSocketNotifier::Read,
this);
541 readNotifier->setEnabled(
false);
542 m_blobIOHandler->setReadChannelSocketNotifier(readNotifier);
547 bool PluginProxy::waitForFinished(
int timeout)
549 return m_process->waitForFinished(timeout);
552 bool PluginProxy::restartIfRequired()
554 if (m_process->state() == QProcess::NotRunning) {
555 TRACE() <<
"RESTART REQUIRED";
#define REMOTEPLUGIN_BIN_PATH
#define PLUGINPROCESS_STOP_TIMEOUT
#define PLUGINPROCESS_START_TIMEOUT
RemotePluginProcess * process