From 53263cde0c471d9cb60484fe5eec72378f69a3e2 Mon Sep 17 00:00:00 2001
From: Alexandre Petit <62973006+AlexpFr@users.noreply.github.com>
Date: Wed, 1 May 2024 16:14:43 +0200
Subject: [PATCH] SSH Agent: Add ssh-add -D function (#8346)
---
share/translations/keepassxc_en.ts | 20 +++++++++++
src/gui/DatabaseWidget.cpp | 10 ++++++
src/gui/DatabaseWidget.h | 1 +
src/gui/MainWindow.cpp | 16 +++++++++
src/gui/MainWindow.ui | 12 +++++++
src/gui/entry/EditEntryWidget.cpp | 12 +++++++
src/gui/entry/EditEntryWidget.h | 1 +
src/gui/entry/EditEntryWidgetSSHAgent.ui | 11 +++++--
src/sshagent/SSHAgent.cpp | 42 ++++++++++++++++++++++++
src/sshagent/SSHAgent.h | 3 ++
10 files changed, 126 insertions(+), 2 deletions(-)
diff --git a/share/translations/keepassxc_en.ts b/share/translations/keepassxc_en.ts
index 2b55841e12..5b06b0aa81 100644
--- a/share/translations/keepassxc_en.ts
+++ b/share/translations/keepassxc_en.ts
@@ -3106,6 +3106,10 @@ Would you like to correct it?
+
+
+
+
EditGroupWidget
@@ -5891,6 +5895,14 @@ We recommend you use the AppImage available on our downloads page.
+
+
+
+
+
+
+
+
ManageDatabase
@@ -9297,6 +9309,14 @@ This option is deprecated, use --set-key-file instead.
+
+
+
+
+
+
+
+
diff --git a/src/gui/DatabaseWidget.cpp b/src/gui/DatabaseWidget.cpp
index 5e7f0c4b0a..2a72ea3ac8 100644
--- a/src/gui/DatabaseWidget.cpp
+++ b/src/gui/DatabaseWidget.cpp
@@ -810,6 +810,16 @@ void DatabaseWidget::removeFromAgent()
m_messageWidget->showMessage(settings.errorString(), MessageWidget::Error);
}
}
+
+void DatabaseWidget::clearSSHAgent()
+{
+ SSHAgent* agent = SSHAgent::instance();
+ if (!agent->clearAllAgentIdentities()) {
+ showMessage(agent->errorString(), MessageWidget::Error);
+ } else {
+ showMessage(agent->errorString(), MessageWidget::Positive);
+ }
+}
#endif
void DatabaseWidget::performAutoType(const QString& sequence)
diff --git a/src/gui/DatabaseWidget.h b/src/gui/DatabaseWidget.h
index 6812600092..6fbdf24107 100644
--- a/src/gui/DatabaseWidget.h
+++ b/src/gui/DatabaseWidget.h
@@ -186,6 +186,7 @@ public slots:
#ifdef WITH_XC_SSHAGENT
void addToAgent();
void removeFromAgent();
+ void clearSSHAgent();
#endif
void performAutoType(const QString& sequence = {});
void performAutoTypeUsername();
diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp
index c89e08f0b9..dc52863d37 100644
--- a/src/gui/MainWindow.cpp
+++ b/src/gui/MainWindow.cpp
@@ -206,6 +206,13 @@ MainWindow::MainWindow()
connect(sshAgent(), SIGNAL(error(QString)), this, SLOT(showErrorMessage(QString)));
connect(sshAgent(), SIGNAL(enabledChanged(bool)), this, SLOT(agentEnabled(bool)));
m_ui->settingsWidget->addSettingsPage(new AgentSettingsPage());
+ if (!sshAgent()->isEnabled()) {
+ m_ui->actionClearSSHAgent->setEnabled(false);
+ m_ui->actionClearSSHAgent->setVisible(false);
+ }
+#else
+ m_ui->actionClearSSHAgent->setVisible(false);
+ m_ui->actionClearSSHAgent->setEnabled(false);
#endif
#if defined(WITH_XC_KEESHARE)
@@ -397,6 +404,9 @@ MainWindow::MainWindow()
m_ui->actionGroupDownloadFavicons->setIcon(icons()->icon("favicon-download"));
m_ui->actionSettings->setIcon(icons()->icon("configure"));
+#ifdef WITH_XC_SSHAGENT
+ m_ui->actionClearSSHAgent->setIcon(icons()->icon("utilities-terminal"));
+#endif
m_ui->actionPasswordGenerator->setIcon(icons()->icon("password-generator"));
m_ui->actionAbout->setIcon(icons()->icon("help-about"));
@@ -509,6 +519,7 @@ MainWindow::MainWindow()
#ifdef WITH_XC_SSHAGENT
m_actionMultiplexer.connect(m_ui->actionEntryAddToAgent, SIGNAL(triggered()), SLOT(addToAgent()));
m_actionMultiplexer.connect(m_ui->actionEntryRemoveFromAgent, SIGNAL(triggered()), SLOT(removeFromAgent()));
+ m_actionMultiplexer.connect(m_ui->actionClearSSHAgent, SIGNAL(triggered()), SLOT(clearSSHAgent()));
#endif
m_actionMultiplexer.connect(m_ui->actionGroupNew, SIGNAL(triggered()), SLOT(createGroup()));
@@ -1601,6 +1612,8 @@ void MainWindow::agentEnabled(bool enabled)
{
m_ui->actionEntryAddToAgent->setVisible(enabled);
m_ui->actionEntryRemoveFromAgent->setVisible(enabled);
+ m_ui->actionClearSSHAgent->setEnabled(enabled);
+ m_ui->actionClearSSHAgent->setVisible(enabled);
}
void MainWindow::showEntryContextMenu(const QPoint& globalPos)
@@ -2110,6 +2123,9 @@ void MainWindow::initActionCollection()
m_ui->actionGroupEmptyRecycleBin,
// Tools Menu
m_ui->actionPasswordGenerator,
+#ifdef WITH_XC_SSHAGENT
+ m_ui->actionClearSSHAgent,
+#endif
m_ui->actionSettings,
// View Menu
m_ui->actionThemeAuto,
diff --git a/src/gui/MainWindow.ui b/src/gui/MainWindow.ui
index 69606b856e..506912f419 100644
--- a/src/gui/MainWindow.ui
+++ b/src/gui/MainWindow.ui
@@ -364,6 +364,7 @@
&Tools
+
diff --git a/src/gui/entry/EditEntryWidget.cpp b/src/gui/entry/EditEntryWidget.cpp
index 7aee16b832..81b1238647 100644
--- a/src/gui/entry/EditEntryWidget.cpp
+++ b/src/gui/entry/EditEntryWidget.cpp
@@ -572,6 +572,7 @@ void EditEntryWidget::setupSSHAgent()
connect(m_sshAgentUi->browseButton, &QPushButton::clicked, this, &EditEntryWidget::browsePrivateKey);
connect(m_sshAgentUi->addToAgentButton, &QPushButton::clicked, this, &EditEntryWidget::addKeyToAgent);
connect(m_sshAgentUi->removeFromAgentButton, &QPushButton::clicked, this, &EditEntryWidget::removeKeyFromAgent);
+ connect(m_sshAgentUi->clearAgentButton, &QPushButton::clicked, this, &EditEntryWidget::clearAgent);
connect(m_sshAgentUi->decryptButton, &QPushButton::clicked, this, &EditEntryWidget::decryptPrivateKey);
connect(m_sshAgentUi->copyToClipboardButton, &QPushButton::clicked, this, &EditEntryWidget::copyPublicKey);
connect(m_sshAgentUi->generateButton, &QPushButton::clicked, this, &EditEntryWidget::generatePrivateKey);
@@ -740,6 +741,7 @@ void EditEntryWidget::updateSSHAgentKeyInfo()
if (sshAgent()->isAgentRunning()) {
m_sshAgentUi->addToAgentButton->setEnabled(true);
m_sshAgentUi->removeFromAgentButton->setEnabled(true);
+ m_sshAgentUi->clearAgentButton->setEnabled(true);
sshAgent()->setAutoRemoveOnLock(key, m_sshAgentUi->removeKeyFromAgentCheckBox->isChecked());
}
@@ -872,6 +874,16 @@ void EditEntryWidget::removeKeyFromAgent()
}
}
+void EditEntryWidget::clearAgent()
+{
+ if (!sshAgent()->clearAllAgentIdentities()) {
+ showMessage(sshAgent()->errorString(), MessageWidget::Error);
+ return;
+ }
+
+ showMessage(sshAgent()->errorString(), MessageWidget::Positive);
+}
+
void EditEntryWidget::decryptPrivateKey()
{
OpenSSHKey key;
diff --git a/src/gui/entry/EditEntryWidget.h b/src/gui/entry/EditEntryWidget.h
index e44bb74305..a1ee1e7032 100644
--- a/src/gui/entry/EditEntryWidget.h
+++ b/src/gui/entry/EditEntryWidget.h
@@ -122,6 +122,7 @@ private slots:
void browsePrivateKey();
void addKeyToAgent();
void removeKeyFromAgent();
+ void clearAgent();
void decryptPrivateKey();
void copyPublicKey();
void generatePrivateKey();
diff --git a/src/gui/entry/EditEntryWidgetSSHAgent.ui b/src/gui/entry/EditEntryWidgetSSHAgent.ui
index 7253e73e8f..286ec1e5df 100644
--- a/src/gui/entry/EditEntryWidgetSSHAgent.ui
+++ b/src/gui/entry/EditEntryWidgetSSHAgent.ui
@@ -27,7 +27,7 @@
0
-
-
+
-
@@ -42,6 +42,13 @@
+ -
+
+
+ Clear agent
+
+
+
-
@@ -221,7 +228,7 @@
0
-
+
Private key
diff --git a/src/sshagent/SSHAgent.cpp b/src/sshagent/SSHAgent.cpp
index 3469117bcc..a436aa6478 100644
--- a/src/sshagent/SSHAgent.cpp
+++ b/src/sshagent/SSHAgent.cpp
@@ -432,6 +432,48 @@ bool SSHAgent::removeIdentity(OpenSSHKey& key)
sendMessage(requestCertificateData, responseCertificateData));
}
+/**
+ * Remove all identities from the SSH agent.
+ *
+ * Since the agent might be forwarded, old or non-OpenSSH, when asked
+ * to remove all keys, attempt to remove both protocol v.1 and v.2
+ * keys.
+ *
+ * @return true on success
+ */
+bool SSHAgent::clearAllAgentIdentities()
+{
+ if (!isAgentRunning()) {
+ m_error = tr("No agent running, cannot remove identity.");
+ return false;
+ }
+
+ bool ret = true;
+ QByteArray requestData;
+ QByteArray responseData;
+ BinaryStream request(&requestData);
+
+ // Same request order as OpenBSD ssh-add: useful?
+ request.write(SSH2_AGENTC_REMOVE_ALL_IDENTITIES);
+
+ if (!sendMessage(requestData, responseData)) {
+ m_error = tr("Failed to remove all SSH identities from agent.");
+ ret = false;
+ }
+
+ request.flush();
+ responseData.clear();
+
+ // Same request order as OpenBSD ssh-add: useful?
+ request.write(SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES);
+
+ // ignore error-code for ssh1
+ sendMessage(requestData, responseData);
+
+ m_error = tr("All SSH identities removed from agent.");
+ return ret;
+}
+
/**
* Get a list of identities from the SSH agent.
*
diff --git a/src/sshagent/SSHAgent.h b/src/sshagent/SSHAgent.h
index 8ef6173a64..d3eeb4ebc9 100644
--- a/src/sshagent/SSHAgent.h
+++ b/src/sshagent/SSHAgent.h
@@ -56,6 +56,7 @@ class SSHAgent : public QObject
bool checkIdentity(const OpenSSHKey& key, bool& loaded);
bool removeIdentity(OpenSSHKey& key);
void removeAllIdentities();
+ bool clearAllAgentIdentities();
void setAutoRemoveOnLock(const OpenSSHKey& key, bool autoRemove);
signals:
@@ -74,6 +75,8 @@ public slots:
const quint8 SSH_AGENTC_ADD_IDENTITY = 17;
const quint8 SSH_AGENTC_REMOVE_IDENTITY = 18;
const quint8 SSH_AGENTC_ADD_ID_CONSTRAINED = 25;
+ const quint8 SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES = 9;
+ const quint8 SSH2_AGENTC_REMOVE_ALL_IDENTITIES = 19;
const quint8 SSH_AGENT_CONSTRAIN_LIFETIME = 1;
const quint8 SSH_AGENT_CONSTRAIN_CONFIRM = 2;