From c34b0069ff3461138823fd275d6ef52d2ef88132 Mon Sep 17 00:00:00 2001 From: Toni Spets Date: Tue, 25 Dec 2018 21:28:02 +0200 Subject: [PATCH] SSH Agent: Add support for OpenSSH for Windows (#1994) * Fixed missing includes in Bootstrap.cpp --- src/core/Bootstrap.cpp | 46 +++++++++++++++++++++++++++- src/core/Tools.cpp | 17 ---------- src/sshagent/AgentSettingsWidget.cpp | 9 ++++++ src/sshagent/AgentSettingsWidget.ui | 7 +++++ src/sshagent/SSHAgent.cpp | 29 +++++++++++++----- src/sshagent/SSHAgent.h | 6 ++-- 6 files changed, 87 insertions(+), 27 deletions(-) diff --git a/src/core/Bootstrap.cpp b/src/core/Bootstrap.cpp index 2d8213b27..cfef7db7b 100644 --- a/src/core/Bootstrap.cpp +++ b/src/core/Bootstrap.cpp @@ -16,6 +16,7 @@ */ #include "Bootstrap.h" +#include "config-keepassx.h" #include "core/Config.h" #include "core/Translator.h" #include "gui/MessageBox.h" @@ -26,6 +27,21 @@ #undef MessageBox #endif +#if defined(HAVE_RLIMIT_CORE) +#include +#endif + +#if defined(HAVE_PR_SET_DUMPABLE) +#include +#endif + +#ifdef HAVE_PT_DENY_ATTACH +// clang-format off +#include +#include +// clang-format on +#endif + namespace Bootstrap { /** @@ -140,6 +156,8 @@ namespace Bootstrap HANDLE hToken = nullptr; PTOKEN_USER pTokenUser = nullptr; DWORD cbBufferSize = 0; + PSID pLocalSystemSid = nullptr; + DWORD pLocalSystemSidSize = SECURITY_MAX_SID_SIZE; // Access control list PACL pACL = nullptr; @@ -166,8 +184,19 @@ namespace Bootstrap goto Cleanup; } + // Retrieve LocalSystem account SID + pLocalSystemSid = static_cast(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 - 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 pACL = static_cast(HeapAlloc(GetProcessHeap(), 0, cbACL)); @@ -189,6 +218,18 @@ namespace Bootstrap 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 bSuccess = ERROR_SUCCESS == SetSecurityInfo(GetCurrentProcess(), // object handle @@ -205,6 +246,9 @@ namespace Bootstrap if (pACL != nullptr) { HeapFree(GetProcessHeap(), 0, pACL); } + if (pLocalSystemSid != nullptr) { + HeapFree(GetProcessHeap(), 0, pLocalSystemSid); + } if (pTokenUser != nullptr) { HeapFree(GetProcessHeap(), 0, pTokenUser); } diff --git a/src/core/Tools.cpp b/src/core/Tools.cpp index 67a8c5f42..495ce9ed8 100644 --- a/src/core/Tools.cpp +++ b/src/core/Tools.cpp @@ -39,23 +39,6 @@ #include // for nanosleep() #endif -#include "config-keepassx.h" - -#if defined(HAVE_RLIMIT_CORE) -#include -#endif - -#if defined(HAVE_PR_SET_DUMPABLE) -#include -#endif - -#ifdef HAVE_PT_DENY_ATTACH -// clang-format off -#include -#include -// clang-format on -#endif - namespace Tools { QString humanReadableFileSize(qint64 bytes, quint32 precision) diff --git a/src/sshagent/AgentSettingsWidget.cpp b/src/sshagent/AgentSettingsWidget.cpp index 6d69e4b61..be23c6906 100644 --- a/src/sshagent/AgentSettingsWidget.cpp +++ b/src/sshagent/AgentSettingsWidget.cpp @@ -26,6 +26,9 @@ AgentSettingsWidget::AgentSettingsWidget(QWidget* parent) , m_ui(new Ui::AgentSettingsWidget()) { m_ui->setupUi(this); +#ifndef Q_OS_WIN + m_ui->useOpenSSHCheckBox->setVisible(false); +#endif } AgentSettingsWidget::~AgentSettingsWidget() @@ -35,9 +38,15 @@ AgentSettingsWidget::~AgentSettingsWidget() void AgentSettingsWidget::loadSettings() { 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() { config()->set("SSHAgent", m_ui->enableSSHAgentCheckBox->isChecked()); +#ifdef Q_OS_WIN + config()->set("SSHAgentOpenSSH", m_ui->useOpenSSHCheckBox->isChecked()); +#endif } diff --git a/src/sshagent/AgentSettingsWidget.ui b/src/sshagent/AgentSettingsWidget.ui index c00c62f39..ff7435abe 100644 --- a/src/sshagent/AgentSettingsWidget.ui +++ b/src/sshagent/AgentSettingsWidget.ui @@ -30,6 +30,13 @@ + + + + Use OpenSSH for Windows instead of Pageant + + + diff --git a/src/sshagent/SSHAgent.cpp b/src/sshagent/SSHAgent.cpp index 6244e8d45..867463d64 100644 --- a/src/sshagent/SSHAgent.cpp +++ b/src/sshagent/SSHAgent.cpp @@ -19,10 +19,10 @@ #include "SSHAgent.h" #include "BinaryStream.h" #include "KeeAgentSettings.h" - -#ifndef Q_OS_WIN +#include "core/Config.h" #include -#else + +#ifdef Q_OS_WIN #include #endif @@ -33,6 +33,8 @@ SSHAgent::SSHAgent(QObject* parent) { #ifndef Q_OS_WIN m_socketPath = QProcessEnvironment::systemEnvironment().value("SSH_AUTH_SOCK"); +#else + m_socketPath = "\\\\.\\pipe\\openssh-ssh-agent"; #endif } @@ -70,13 +72,22 @@ bool SSHAgent::isAgentRunning() const #ifndef Q_OS_WIN return !m_socketPath.isEmpty(); #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 } 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; BinaryStream stream(&socket); @@ -97,7 +108,11 @@ bool SSHAgent::sendMessage(const QByteArray& in, QByteArray& out) socket.close(); return true; -#else +} + +#ifdef Q_OS_WIN +bool SSHAgent::sendMessagePageant(const QByteArray& in, QByteArray& out) +{ HWND hWnd = FindWindowA("Pageant", "Pageant"); if (!hWnd) { @@ -157,8 +172,8 @@ bool SSHAgent::sendMessage(const QByteArray& in, QByteArray& out) CloseHandle(handle); return (res > 0); -#endif } +#endif /** * Add the identity to the SSH agent. diff --git a/src/sshagent/SSHAgent.h b/src/sshagent/SSHAgent.h index 4311a911a..1b2bcad27 100644 --- a/src/sshagent/SSHAgent.h +++ b/src/sshagent/SSHAgent.h @@ -62,12 +62,14 @@ private: ~SSHAgent(); bool sendMessage(const QByteArray& in, QByteArray& out); +#ifdef Q_OS_WIN + bool sendMessagePageant(const QByteArray& in, QByteArray& out); +#endif static SSHAgent* m_instance; -#ifndef Q_OS_WIN QString m_socketPath; -#else +#ifdef Q_OS_WIN const quint32 AGENT_MAX_MSGLEN = 8192; const quint32 AGENT_COPYDATA_ID = 0x804e50ba; #endif