From 7e0c87218c64eb64d6d29e2dcbe34cb36de6ff50 Mon Sep 17 00:00:00 2001 From: Alexandre Petit <62973006+AlexpFr@users.noreply.github.com> Date: Sat, 27 Apr 2024 23:22:08 +0200 Subject: [PATCH] SSH Agent: Add ssh-add -D function (#8346) --- src/gui/DatabaseWidget.cpp | 10 ++++++ src/gui/DatabaseWidget.h | 1 + src/gui/MainWindow.cpp | 6 ++++ src/gui/MainWindow.ui | 12 +++++++ src/gui/entry/EditEntryWidget.cpp | 12 +++++++ src/gui/entry/EditEntryWidget.h | 1 + src/gui/entry/EditEntryWidgetSSHAgent.ui | 9 ++++- src/sshagent/SSHAgent.cpp | 42 ++++++++++++++++++++++++ src/sshagent/SSHAgent.h | 3 ++ 9 files changed, 95 insertions(+), 1 deletion(-) diff --git a/src/gui/DatabaseWidget.cpp b/src/gui/DatabaseWidget.cpp index 5e7f0c4b0a..46fb9eb893 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::flushSSHAgent() +{ + SSHAgent* agent = SSHAgent::instance(); + if (!agent->flushAllAgentIdentities()) { + 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..1b226818c5 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 flushSSHAgent(); #endif void performAutoType(const QString& sequence = {}); void performAutoTypeUsername(); diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index c89e08f0b9..8147c40b97 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -398,6 +398,7 @@ MainWindow::MainWindow() m_ui->actionSettings->setIcon(icons()->icon("configure")); m_ui->actionPasswordGenerator->setIcon(icons()->icon("password-generator")); + m_ui->actionFlushSSHAgent->setIcon(icons()->icon("utilities-terminal")); m_ui->actionAbout->setIcon(icons()->icon("help-about")); m_ui->actionDonate->setIcon(icons()->icon("donate")); @@ -509,6 +510,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->actionFlushSSHAgent, SIGNAL(triggered()), SLOT(flushSSHAgent())); #endif m_actionMultiplexer.connect(m_ui->actionGroupNew, SIGNAL(triggered()), SLOT(createGroup())); @@ -967,6 +969,8 @@ void MainWindow::setMenuActionState(DatabaseWidget::Mode mode) m_ui->actionEntryAddToAgent->setEnabled(singleEntryHasSshKey); m_ui->actionEntryRemoveFromAgent->setVisible(singleEntryHasSshKey); m_ui->actionEntryRemoveFromAgent->setEnabled(singleEntryHasSshKey); + m_ui->actionFlushSSHAgent->setVisible(true); + m_ui->actionFlushSSHAgent->setEnabled(true); #endif m_searchWidgetAction->setEnabled(true); @@ -1601,6 +1605,7 @@ void MainWindow::agentEnabled(bool enabled) { m_ui->actionEntryAddToAgent->setVisible(enabled); m_ui->actionEntryRemoveFromAgent->setVisible(enabled); + m_ui->actionFlushSSHAgent->setVisible(enabled); } void MainWindow::showEntryContextMenu(const QPoint& globalPos) @@ -2110,6 +2115,7 @@ void MainWindow::initActionCollection() m_ui->actionGroupEmptyRecycleBin, // Tools Menu m_ui->actionPasswordGenerator, + m_ui->actionFlushSSHAgent, m_ui->actionSettings, // View Menu m_ui->actionThemeAuto, diff --git a/src/gui/MainWindow.ui b/src/gui/MainWindow.ui index 69606b856e..2ebfc98ce3 100644 --- a/src/gui/MainWindow.ui +++ b/src/gui/MainWindow.ui @@ -364,6 +364,7 @@ &Tools + @@ -1291,6 +1292,17 @@ Import… + + + Flush SSH Agent + + + Flush identities like ssh-add -D + + + QAction::TextHeuristicRole + + diff --git a/src/gui/entry/EditEntryWidget.cpp b/src/gui/entry/EditEntryWidget.cpp index 6620b08077..e2cd866480 100644 --- a/src/gui/entry/EditEntryWidget.cpp +++ b/src/gui/entry/EditEntryWidget.cpp @@ -565,6 +565,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->flushAgentButton, &QPushButton::clicked, this, &EditEntryWidget::flushAgent); 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); @@ -684,6 +685,7 @@ void EditEntryWidget::updateSSHAgentKeyInfo() if (sshAgent()->isAgentRunning()) { m_sshAgentUi->addToAgentButton->setEnabled(true); m_sshAgentUi->removeFromAgentButton->setEnabled(true); + m_sshAgentUi->flushAgentButton->setEnabled(true); sshAgent()->setAutoRemoveOnLock(key, m_sshAgentUi->removeKeyFromAgentCheckBox->isChecked()); } @@ -786,6 +788,16 @@ void EditEntryWidget::removeKeyFromAgent() } } +void EditEntryWidget::flushAgent() +{ + if (!sshAgent()->flushAllAgentIdentities()) { + 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 0507b5dfbc..050eea7a2f 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 flushAgent(); void decryptPrivateKey(); void copyPublicKey(); void generatePrivateKey(); diff --git a/src/gui/entry/EditEntryWidgetSSHAgent.ui b/src/gui/entry/EditEntryWidgetSSHAgent.ui index 3fa48baf33..faa6d62ef9 100644 --- a/src/gui/entry/EditEntryWidgetSSHAgent.ui +++ b/src/gui/entry/EditEntryWidgetSSHAgent.ui @@ -139,7 +139,7 @@ - + @@ -154,6 +154,13 @@ + + + + Flush agent + + + diff --git a/src/sshagent/SSHAgent.cpp b/src/sshagent/SSHAgent.cpp index 5c423cc755..5e8514c412 100644 --- a/src/sshagent/SSHAgent.cpp +++ b/src/sshagent/SSHAgent.cpp @@ -363,6 +363,48 @@ bool SSHAgent::removeIdentity(OpenSSHKey& key) return sendMessage(requestData, responseData); } +/** + * Flush 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::flushAllAgentIdentities() +{ + 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..eeb3bda103 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 flushAllAgentIdentities(); 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;