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