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()));
441 void PluginProxy::onReadStandardError()
443 QString ba = QString::fromLatin1(m_process->readAllStandardError());
446 void PluginProxy::onExit(
int exitCode, QProcess::ExitStatus exitStatus)
448 TRACE() <<
"Plugin process exit with code " << exitCode <<
451 if (m_isProcessing || exitStatus == QProcess::CrashExit) {
452 qCritical() <<
"Challenge produces CRASH!";
453 emit processError(Error::InternalServer,
454 QLatin1String(
"plugin processed crashed"));
457 TRACE() <<
"plugin process terminated because cannot change user";
460 m_isProcessing =
false;
463 void PluginProxy::onError(QProcess::ProcessError err)
465 TRACE() <<
"Error: " << err;
468 QString PluginProxy::queryType()
472 if (!restartIfRequired())
475 QDataStream ds(m_process);
476 ds << (quint32)PLUGIN_OP_TYPE;
482 qCritical(
"PluginProxy returned NULL result");
485 QDataStream out(buffer);
490 QStringList PluginProxy::queryMechanisms()
494 if (!restartIfRequired())
495 return QStringList();
497 QDataStream in(m_process);
498 in << (quint32)PLUGIN_OP_MECHANISMS;
506 QVariant mechanismsVar;
507 QDataStream out(buffer);
509 out >> mechanismsVar;
510 QVariantList varList = mechanismsVar.toList();
512 for (
int i = 0; i < varList.count(); i++)
513 strList << varList.at(i).toString();
517 qCritical(
"PluginProxy returned NULL result");
522 bool PluginProxy::waitForStarted(
int timeout)
524 if (!m_process->waitForStarted(timeout))
527 m_blobIOHandler =
new BlobIOHandler(m_process, m_process,
this);
529 connect(m_blobIOHandler,
530 SIGNAL(dataReceived(
const QVariantMap &)),
532 SLOT(sessionDataReceived(
const QVariantMap &)));
534 QSocketNotifier *readNotifier =
535 new QSocketNotifier(STDIN_FILENO, QSocketNotifier::Read,
this);
537 readNotifier->setEnabled(
false);
538 m_blobIOHandler->setReadChannelSocketNotifier(readNotifier);
543 bool PluginProxy::waitForFinished(
int timeout)
545 return m_process->waitForFinished(timeout);
548 bool PluginProxy::restartIfRequired()
550 if (m_process->state() == QProcess::NotRunning) {
551 TRACE() <<
"RESTART REQUIRED";
#define REMOTEPLUGIN_BIN_PATH
#define PLUGINPROCESS_STOP_TIMEOUT
#define PLUGINPROCESS_START_TIMEOUT
RemotePluginProcess * process