diff --git a/share/translations/keepassxc_en.ts b/share/translations/keepassxc_en.ts index 1bc3afec6..a712f32f1 100644 --- a/share/translations/keepassxc_en.ts +++ b/share/translations/keepassxc_en.ts @@ -3410,6 +3410,10 @@ Would you like to correct it? seconds + + Clear agent + + EditGroupWidget @@ -6288,6 +6292,14 @@ Expect some bugs and minor issues, this version is meant for testing purposes.E&xpire Entry… + + Clear SSH Agent + + + + Clear all identities in ssh-agent + + ManageDatabase @@ -9811,6 +9823,14 @@ This option is deprecated, use --set-key-file instead. No agent running, cannot list identities. + + Failed to remove all SSH identities from agent. + + + + All SSH identities removed from agent. + + SearchHelpWidget diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index 563f20a46..0182121fa 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -211,7 +211,10 @@ MainWindow::MainWindow() #ifdef WITH_XC_SSHAGENT connect(sshAgent(), SIGNAL(error(QString)), this, SLOT(showErrorMessage(QString))); connect(sshAgent(), SIGNAL(enabledChanged(bool)), this, SLOT(agentEnabled(bool))); + connect(m_ui->actionClearSSHAgent, SIGNAL(triggered()), SLOT(clearSSHAgent())); m_ui->settingsWidget->addSettingsPage(new AgentSettingsPage()); +#else + agentEnabled(false); #endif #if defined(WITH_XC_KEESHARE) @@ -414,6 +417,7 @@ MainWindow::MainWindow() m_ui->actionSettings->setIcon(icons()->icon("configure")); m_ui->actionPasswordGenerator->setIcon(icons()->icon("password-generator")); + m_ui->actionClearSSHAgent->setIcon(icons()->icon("utilities-terminal")); m_ui->actionAbout->setIcon(icons()->icon("help-about")); m_ui->actionDonate->setIcon(icons()->icon("donate")); @@ -970,6 +974,8 @@ void MainWindow::updateMenuActionState() m_ui->actionEntryAddToAgent->setEnabled(hasSSHKey); m_ui->actionEntryRemoveFromAgent->setVisible(hasSSHKey); m_ui->actionEntryRemoveFromAgent->setEnabled(hasSSHKey); + m_ui->actionClearSSHAgent->setVisible(sshAgent()->isEnabled()); + m_ui->actionClearSSHAgent->setEnabled(sshAgent()->isEnabled()); #endif m_ui->actionGroupNew->setEnabled(groupSelected && !inRecycleBin); @@ -1460,6 +1466,15 @@ void MainWindow::disableMenuAndToolbar() m_ui->menubar->setDisabled(true); } +void MainWindow::clearSSHAgent() +{ +#ifdef WITH_XC_SSHAGENT + auto agent = SSHAgent::instance(); + auto ret = agent->clearAllAgentIdentities(); + displayGlobalMessage(agent->errorString(), ret ? MessageWidget::Positive : KMessageWidget::Error, false); +#endif +} + void MainWindow::saveWindowInformation() { if (isVisible()) { @@ -1585,6 +1600,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) @@ -2078,6 +2095,7 @@ void MainWindow::initActionCollection() m_ui->actionGroupEmptyRecycleBin, // Tools Menu m_ui->actionPasswordGenerator, + m_ui->actionClearSSHAgent, m_ui->actionSettings, // View Menu m_ui->actionThemeAuto, diff --git a/src/gui/MainWindow.h b/src/gui/MainWindow.h index b607a4566..ecd98e03a 100644 --- a/src/gui/MainWindow.h +++ b/src/gui/MainWindow.h @@ -155,6 +155,7 @@ private slots: void focusSearchWidget(); void enableMenuAndToolbar(); void disableMenuAndToolbar(); + void clearSSHAgent(); private: static const QString BaseWindowTitle; diff --git a/src/gui/MainWindow.ui b/src/gui/MainWindow.ui index c84727c3e..fc4c0b9d5 100644 --- a/src/gui/MainWindow.ui +++ b/src/gui/MainWindow.ui @@ -369,6 +369,7 @@ &Tools + @@ -1312,6 +1313,17 @@ Toggle Show Group Panel + + + Clear SSH Agent + + + Clear all identities in ssh-agent + + + QAction::TextHeuristicRole + + diff --git a/src/gui/entry/EditEntryWidget.cpp b/src/gui/entry/EditEntryWidget.cpp index 9af9aa601..d2213a669 100644 --- a/src/gui/entry/EditEntryWidget.cpp +++ b/src/gui/entry/EditEntryWidget.cpp @@ -606,6 +606,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); @@ -719,6 +720,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()); } @@ -821,6 +823,12 @@ void EditEntryWidget::removeKeyFromAgent() } } +void EditEntryWidget::clearAgent() +{ + auto ret = sshAgent()->clearAllAgentIdentities(); + showMessage(sshAgent()->errorString(), ret ? MessageWidget::Positive : KMessageWidget::Error); +} + void EditEntryWidget::decryptPrivateKey() { OpenSSHKey key; diff --git a/src/gui/entry/EditEntryWidget.h b/src/gui/entry/EditEntryWidget.h index 323a85b8f..3fce4d56d 100644 --- a/src/gui/entry/EditEntryWidget.h +++ b/src/gui/entry/EditEntryWidget.h @@ -135,6 +135,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 3fa48baf3..3215c1a27 100644 --- a/src/gui/entry/EditEntryWidgetSSHAgent.ui +++ b/src/gui/entry/EditEntryWidgetSSHAgent.ui @@ -139,7 +139,7 @@ - + @@ -154,6 +154,13 @@ + + + + Clear agent + + + diff --git a/src/sshagent/SSHAgent.cpp b/src/sshagent/SSHAgent.cpp index 5c423cc75..a8aa695ce 100644 --- a/src/sshagent/SSHAgent.cpp +++ b/src/sshagent/SSHAgent.cpp @@ -363,6 +363,48 @@ bool SSHAgent::removeIdentity(OpenSSHKey& key) return sendMessage(requestData, responseData); } +/** + * 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); + + // SSH2 Identity Removal + 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(); + + // SSH1 Identity Removal + 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 8ef6173a6..d3eeb4ebc 100644 --- a/src/sshagent/SSHAgent.h +++ b/src/sshagent/SSHAgent.h @@ -56,6 +56,7 @@ public: 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 @@ private: 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;