SSH Agent: Add support for OpenSSH for Windows (#1994)

* Fixed missing includes in Bootstrap.cpp
This commit is contained in:
Toni Spets 2018-12-25 21:28:02 +02:00 committed by Jonathan White
parent 5488f1bfc3
commit c34b0069ff
6 changed files with 87 additions and 27 deletions

View File

@ -16,6 +16,7 @@
*/ */
#include "Bootstrap.h" #include "Bootstrap.h"
#include "config-keepassx.h"
#include "core/Config.h" #include "core/Config.h"
#include "core/Translator.h" #include "core/Translator.h"
#include "gui/MessageBox.h" #include "gui/MessageBox.h"
@ -26,6 +27,21 @@
#undef MessageBox #undef MessageBox
#endif #endif
#if defined(HAVE_RLIMIT_CORE)
#include <sys/resource.h>
#endif
#if defined(HAVE_PR_SET_DUMPABLE)
#include <sys/prctl.h>
#endif
#ifdef HAVE_PT_DENY_ATTACH
// clang-format off
#include <sys/types.h>
#include <sys/ptrace.h>
// clang-format on
#endif
namespace Bootstrap namespace Bootstrap
{ {
/** /**
@ -140,6 +156,8 @@ namespace Bootstrap
HANDLE hToken = nullptr; HANDLE hToken = nullptr;
PTOKEN_USER pTokenUser = nullptr; PTOKEN_USER pTokenUser = nullptr;
DWORD cbBufferSize = 0; DWORD cbBufferSize = 0;
PSID pLocalSystemSid = nullptr;
DWORD pLocalSystemSidSize = SECURITY_MAX_SID_SIZE;
// Access control list // Access control list
PACL pACL = nullptr; PACL pACL = nullptr;
@ -166,8 +184,19 @@ namespace Bootstrap
goto Cleanup; goto Cleanup;
} }
// Retrieve LocalSystem account SID
pLocalSystemSid = static_cast<PSID>(HeapAlloc(GetProcessHeap(), 0, pLocalSystemSidSize));
if (pLocalSystemSid == nullptr) {
goto Cleanup;
}
if (!CreateWellKnownSid(WinLocalSystemSid, nullptr, pLocalSystemSid, &pLocalSystemSidSize)) {
goto Cleanup;
}
// Calculate the amount of memory that must be allocated for the DACL // Calculate the amount of memory that must be allocated for the DACL
cbACL = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(pTokenUser->User.Sid); cbACL = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(pTokenUser->User.Sid)
+ sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(pLocalSystemSid);
// Create and initialize an ACL // Create and initialize an ACL
pACL = static_cast<PACL>(HeapAlloc(GetProcessHeap(), 0, cbACL)); pACL = static_cast<PACL>(HeapAlloc(GetProcessHeap(), 0, cbACL));
@ -189,6 +218,18 @@ namespace Bootstrap
goto Cleanup; goto Cleanup;
} }
#ifdef WITH_XC_SSHAGENT
// OpenSSH for Windows ssh-agent service is running as LocalSystem
if (!AddAccessAllowedAce(
pACL,
ACL_REVISION,
PROCESS_QUERY_INFORMATION | PROCESS_DUP_HANDLE, // just enough for ssh-agent
pLocalSystemSid // known LocalSystem sid
)) {
goto Cleanup;
}
#endif
// Set discretionary access control list // Set discretionary access control list
bSuccess = ERROR_SUCCESS bSuccess = ERROR_SUCCESS
== SetSecurityInfo(GetCurrentProcess(), // object handle == SetSecurityInfo(GetCurrentProcess(), // object handle
@ -205,6 +246,9 @@ namespace Bootstrap
if (pACL != nullptr) { if (pACL != nullptr) {
HeapFree(GetProcessHeap(), 0, pACL); HeapFree(GetProcessHeap(), 0, pACL);
} }
if (pLocalSystemSid != nullptr) {
HeapFree(GetProcessHeap(), 0, pLocalSystemSid);
}
if (pTokenUser != nullptr) { if (pTokenUser != nullptr) {
HeapFree(GetProcessHeap(), 0, pTokenUser); HeapFree(GetProcessHeap(), 0, pTokenUser);
} }

View File

@ -39,23 +39,6 @@
#include <time.h> // for nanosleep() #include <time.h> // for nanosleep()
#endif #endif
#include "config-keepassx.h"
#if defined(HAVE_RLIMIT_CORE)
#include <sys/resource.h>
#endif
#if defined(HAVE_PR_SET_DUMPABLE)
#include <sys/prctl.h>
#endif
#ifdef HAVE_PT_DENY_ATTACH
// clang-format off
#include <sys/types.h>
#include <sys/ptrace.h>
// clang-format on
#endif
namespace Tools namespace Tools
{ {
QString humanReadableFileSize(qint64 bytes, quint32 precision) QString humanReadableFileSize(qint64 bytes, quint32 precision)

View File

@ -26,6 +26,9 @@ AgentSettingsWidget::AgentSettingsWidget(QWidget* parent)
, m_ui(new Ui::AgentSettingsWidget()) , m_ui(new Ui::AgentSettingsWidget())
{ {
m_ui->setupUi(this); m_ui->setupUi(this);
#ifndef Q_OS_WIN
m_ui->useOpenSSHCheckBox->setVisible(false);
#endif
} }
AgentSettingsWidget::~AgentSettingsWidget() AgentSettingsWidget::~AgentSettingsWidget()
@ -35,9 +38,15 @@ AgentSettingsWidget::~AgentSettingsWidget()
void AgentSettingsWidget::loadSettings() void AgentSettingsWidget::loadSettings()
{ {
m_ui->enableSSHAgentCheckBox->setChecked(config()->get("SSHAgent", false).toBool()); m_ui->enableSSHAgentCheckBox->setChecked(config()->get("SSHAgent", false).toBool());
#ifdef Q_OS_WIN
m_ui->useOpenSSHCheckBox->setChecked(config()->get("SSHAgentOpenSSH", false).toBool());
#endif
} }
void AgentSettingsWidget::saveSettings() void AgentSettingsWidget::saveSettings()
{ {
config()->set("SSHAgent", m_ui->enableSSHAgentCheckBox->isChecked()); config()->set("SSHAgent", m_ui->enableSSHAgentCheckBox->isChecked());
#ifdef Q_OS_WIN
config()->set("SSHAgentOpenSSH", m_ui->useOpenSSHCheckBox->isChecked());
#endif
} }

View File

@ -30,6 +30,13 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QCheckBox" name="useOpenSSHCheckBox">
<property name="text">
<string>Use OpenSSH for Windows instead of Pageant</string>
</property>
</widget>
</item>
<item> <item>
<spacer name="verticalSpacer"> <spacer name="verticalSpacer">
<property name="orientation"> <property name="orientation">

View File

@ -19,10 +19,10 @@
#include "SSHAgent.h" #include "SSHAgent.h"
#include "BinaryStream.h" #include "BinaryStream.h"
#include "KeeAgentSettings.h" #include "KeeAgentSettings.h"
#include "core/Config.h"
#ifndef Q_OS_WIN
#include <QtNetwork> #include <QtNetwork>
#else
#ifdef Q_OS_WIN
#include <windows.h> #include <windows.h>
#endif #endif
@ -33,6 +33,8 @@ SSHAgent::SSHAgent(QObject* parent)
{ {
#ifndef Q_OS_WIN #ifndef Q_OS_WIN
m_socketPath = QProcessEnvironment::systemEnvironment().value("SSH_AUTH_SOCK"); m_socketPath = QProcessEnvironment::systemEnvironment().value("SSH_AUTH_SOCK");
#else
m_socketPath = "\\\\.\\pipe\\openssh-ssh-agent";
#endif #endif
} }
@ -70,13 +72,22 @@ bool SSHAgent::isAgentRunning() const
#ifndef Q_OS_WIN #ifndef Q_OS_WIN
return !m_socketPath.isEmpty(); return !m_socketPath.isEmpty();
#else #else
return (FindWindowA("Pageant", "Pageant") != nullptr); if (!config()->get("SSHAgentOpenSSH").toBool()) {
return (FindWindowA("Pageant", "Pageant") != nullptr);
} else {
return WaitNamedPipe(m_socketPath.toLatin1().data(), 100);
}
#endif #endif
} }
bool SSHAgent::sendMessage(const QByteArray& in, QByteArray& out) bool SSHAgent::sendMessage(const QByteArray& in, QByteArray& out)
{ {
#ifndef Q_OS_WIN #ifdef Q_OS_WIN
if (!config()->get("SSHAgentOpenSSH").toBool()) {
return sendMessagePageant(in, out);
}
#endif
QLocalSocket socket; QLocalSocket socket;
BinaryStream stream(&socket); BinaryStream stream(&socket);
@ -97,7 +108,11 @@ bool SSHAgent::sendMessage(const QByteArray& in, QByteArray& out)
socket.close(); socket.close();
return true; return true;
#else }
#ifdef Q_OS_WIN
bool SSHAgent::sendMessagePageant(const QByteArray& in, QByteArray& out)
{
HWND hWnd = FindWindowA("Pageant", "Pageant"); HWND hWnd = FindWindowA("Pageant", "Pageant");
if (!hWnd) { if (!hWnd) {
@ -157,8 +172,8 @@ bool SSHAgent::sendMessage(const QByteArray& in, QByteArray& out)
CloseHandle(handle); CloseHandle(handle);
return (res > 0); return (res > 0);
#endif
} }
#endif
/** /**
* Add the identity to the SSH agent. * Add the identity to the SSH agent.

View File

@ -62,12 +62,14 @@ private:
~SSHAgent(); ~SSHAgent();
bool sendMessage(const QByteArray& in, QByteArray& out); bool sendMessage(const QByteArray& in, QByteArray& out);
#ifdef Q_OS_WIN
bool sendMessagePageant(const QByteArray& in, QByteArray& out);
#endif
static SSHAgent* m_instance; static SSHAgent* m_instance;
#ifndef Q_OS_WIN
QString m_socketPath; QString m_socketPath;
#else #ifdef Q_OS_WIN
const quint32 AGENT_MAX_MSGLEN = 8192; const quint32 AGENT_MAX_MSGLEN = 8192;
const quint32 AGENT_COPYDATA_ID = 0x804e50ba; const quint32 AGENT_COPYDATA_ID = 0x804e50ba;
#endif #endif