Skip to content

Commit

Permalink
SSH Agent: Add ssh-add -D function (keepassxreboot#8346)
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexpFr committed May 12, 2024
1 parent c47108a commit e903cea
Show file tree
Hide file tree
Showing 10 changed files with 126 additions and 2 deletions.
20 changes: 20 additions & 0 deletions share/translations/keepassxc_en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3106,6 +3106,10 @@ Would you like to correct it?</source>
<source>Certificate</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Clear agent</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>EditGroupWidget</name>
Expand Down Expand Up @@ -5891,6 +5895,14 @@ We recommend you use the AppImage available on our downloads page.</source>
<source>Toggle Allow Screen Capture</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Clear SSH Agent</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Clear all identities like ssh-add -D</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ManageDatabase</name>
Expand Down Expand Up @@ -9297,6 +9309,14 @@ This option is deprecated, use --set-key-file instead.</source>
<source>No agent running, cannot list identities.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Failed to remove all SSH identities from agent.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>All SSH identities removed from agent.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Agent refused this identity certificate. Possible reasons include:</source>
<translation type="unfinished"></translation>
Expand Down
10 changes: 10 additions & 0 deletions src/gui/DatabaseWidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions src/gui/DatabaseWidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ public slots:
#ifdef WITH_XC_SSHAGENT
void addToAgent();
void removeFromAgent();
void clearSSHAgent();
#endif
void performAutoType(const QString& sequence = {});
void performAutoTypeUsername();
Expand Down
16 changes: 16 additions & 0 deletions src/gui/MainWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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"));
Expand Down Expand Up @@ -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()));
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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,
Expand Down
12 changes: 12 additions & 0 deletions src/gui/MainWindow.ui
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,7 @@
<string>&amp;Tools</string>
</property>
<addaction name="actionPasswordGenerator"/>
<addaction name="actionClearSSHAgent"/>
<addaction name="actionSettings"/>
</widget>
<widget class="QMenu" name="menuView">
Expand Down Expand Up @@ -1291,6 +1292,17 @@
<string>Import…</string>
</property>
</action>
<action name="actionClearSSHAgent">
<property name="text">
<string>Clear SSH Agent</string>
</property>
<property name="toolTip">
<string>Clear all identities like ssh-add -D</string>
</property>
<property name="menuRole">
<enum>QAction::TextHeuristicRole</enum>
</property>
</action>
</widget>
<customwidgets>
<customwidget>
Expand Down
12 changes: 12 additions & 0 deletions src/gui/entry/EditEntryWidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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());
}
Expand Down Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions src/gui/entry/EditEntryWidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ private slots:
void browsePrivateKey();
void addKeyToAgent();
void removeKeyFromAgent();
void clearAgent();
void decryptPrivateKey();
void copyPublicKey();
void generatePrivateKey();
Expand Down
11 changes: 9 additions & 2 deletions src/gui/entry/EditEntryWidgetSSHAgent.ui
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
<number>0</number>
</property>
<item row="6" column="2">
<layout class="QHBoxLayout" name="agentActionsLayout" stretch="0,0">
<layout class="QHBoxLayout" name="agentActionsLayout" stretch="0,0,0">
<item>
<widget class="QPushButton" name="addToAgentButton">
<property name="text">
Expand All @@ -42,6 +42,13 @@
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="clearAgentButton">
<property name="text">
<string>Clear agent</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="1" colspan="3">
Expand Down Expand Up @@ -221,7 +228,7 @@
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="privateKeyTabWidgetPage1" native="true">
<widget class="QWidget" name="privateKeyTabWidgetPage1">
<attribute name="title">
<string>Private key</string>
</attribute>
Expand Down
42 changes: 42 additions & 0 deletions src/sshagent/SSHAgent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand Down
3 changes: 3 additions & 0 deletions src/sshagent/SSHAgent.h
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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;
Expand Down

0 comments on commit e903cea

Please sign in to comment.