Fix SSH askpass helper text-file-busy race
This commit is contained in:
@@ -4,8 +4,8 @@
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QProcessEnvironment>
|
||||
#include <QTemporaryFile>
|
||||
#include <QTextStream>
|
||||
#include <QUuid>
|
||||
|
||||
namespace {
|
||||
QString escapeForShellSingleQuotes(const QString& value)
|
||||
@@ -33,8 +33,7 @@ SshSessionBackend::SshSessionBackend(const Profile& profile, QObject* parent)
|
||||
m_connectedProbeTimer(new QTimer(this)),
|
||||
m_state(SessionState::Disconnected),
|
||||
m_userInitiatedDisconnect(false),
|
||||
m_reconnectPending(false),
|
||||
m_askPassScript(nullptr)
|
||||
m_reconnectPending(false)
|
||||
{
|
||||
m_connectedProbeTimer->setSingleShot(true);
|
||||
|
||||
@@ -325,21 +324,26 @@ bool SshSessionBackend::configureAskPass(const SessionConnectOptions& options,
|
||||
QProcessEnvironment& environment,
|
||||
QString& error)
|
||||
{
|
||||
cleanupAskPassScript();
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
m_askPassScript = new QTemporaryFile(QDir::tempPath() + QStringLiteral("/orbithub_askpass_XXXXXX.cmd"),
|
||||
this);
|
||||
m_askPassScriptPath = QDir::temp().filePath(
|
||||
QStringLiteral("orbithub_askpass_%1.cmd")
|
||||
.arg(QUuid::createUuid().toString(QUuid::WithoutBraces)));
|
||||
#else
|
||||
m_askPassScript = new QTemporaryFile(QDir::tempPath() + QStringLiteral("/orbithub_askpass_XXXXXX.sh"),
|
||||
this);
|
||||
m_askPassScriptPath = QDir::temp().filePath(
|
||||
QStringLiteral("orbithub_askpass_%1.sh")
|
||||
.arg(QUuid::createUuid().toString(QUuid::WithoutBraces)));
|
||||
#endif
|
||||
|
||||
if (!m_askPassScript->open()) {
|
||||
QFile script(m_askPassScriptPath);
|
||||
if (!script.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) {
|
||||
error = QStringLiteral("Failed to create temporary askpass helper script.");
|
||||
cleanupAskPassScript();
|
||||
return false;
|
||||
}
|
||||
|
||||
QTextStream out(m_askPassScript);
|
||||
QTextStream out(&script);
|
||||
#ifdef Q_OS_WIN
|
||||
out << "@echo off\r\n";
|
||||
out << "echo " << escapedForWindowsEcho(options.password) << "\r\n";
|
||||
@@ -348,15 +352,18 @@ bool SshSessionBackend::configureAskPass(const SessionConnectOptions& options,
|
||||
out << "printf '%s\\n' '" << escapeForShellSingleQuotes(options.password) << "'\n";
|
||||
#endif
|
||||
out.flush();
|
||||
m_askPassScript->flush();
|
||||
m_askPassScript->close();
|
||||
script.close();
|
||||
|
||||
#ifndef Q_OS_WIN
|
||||
QFile::setPermissions(m_askPassScript->fileName(),
|
||||
QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner);
|
||||
if (!QFile::setPermissions(m_askPassScriptPath,
|
||||
QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner)) {
|
||||
error = QStringLiteral("Failed to set permissions on askpass helper script.");
|
||||
cleanupAskPassScript();
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
environment.insert(QStringLiteral("SSH_ASKPASS"), m_askPassScript->fileName());
|
||||
environment.insert(QStringLiteral("SSH_ASKPASS"), m_askPassScriptPath);
|
||||
environment.insert(QStringLiteral("SSH_ASKPASS_REQUIRE"), QStringLiteral("force"));
|
||||
if (!environment.contains(QStringLiteral("DISPLAY"))) {
|
||||
environment.insert(QStringLiteral("DISPLAY"), QStringLiteral(":0"));
|
||||
@@ -367,9 +374,9 @@ bool SshSessionBackend::configureAskPass(const SessionConnectOptions& options,
|
||||
|
||||
void SshSessionBackend::cleanupAskPassScript()
|
||||
{
|
||||
if (m_askPassScript != nullptr) {
|
||||
delete m_askPassScript;
|
||||
m_askPassScript = nullptr;
|
||||
if (!m_askPassScriptPath.isEmpty()) {
|
||||
QFile::remove(m_askPassScriptPath);
|
||||
m_askPassScriptPath.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -402,6 +409,9 @@ QString SshSessionBackend::mapSshError(const QString& rawError) const
|
||||
if (raw.contains(QStringLiteral("No such file or directory"), Qt::CaseInsensitive)) {
|
||||
return QStringLiteral("Required file was not found.");
|
||||
}
|
||||
if (raw.contains(QStringLiteral("Text file busy"), Qt::CaseInsensitive)) {
|
||||
return QStringLiteral("Credential helper could not start (text file busy). Retry the connection.");
|
||||
}
|
||||
if (raw.isEmpty()) {
|
||||
return QStringLiteral("SSH connection failed for an unknown reason.");
|
||||
}
|
||||
|
||||
@@ -7,8 +7,6 @@
|
||||
#include <QString>
|
||||
#include <QTimer>
|
||||
|
||||
class QTemporaryFile;
|
||||
|
||||
class SshSessionBackend : public SessionBackend
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -37,7 +35,7 @@ private:
|
||||
bool m_reconnectPending;
|
||||
SessionConnectOptions m_reconnectOptions;
|
||||
QString m_lastRawError;
|
||||
QTemporaryFile* m_askPassScript;
|
||||
QString m_askPassScriptPath;
|
||||
|
||||
void setState(SessionState state, const QString& message);
|
||||
bool startSshProcess(const SessionConnectOptions& options);
|
||||
|
||||
Reference in New Issue
Block a user