SSH Agent: Show error messages if something fails

This commit is contained in:
Toni Spets 2018-03-03 17:49:00 +02:00 committed by Janek Bevendorff
parent 4ce0005711
commit 084758908a
5 changed files with 69 additions and 13 deletions

View file

@ -198,6 +198,7 @@ MainWindow::MainWindow()
#endif #endif
#ifdef WITH_XC_SSHAGENT #ifdef WITH_XC_SSHAGENT
SSHAgent::init(this); SSHAgent::init(this);
connect(SSHAgent::instance(), SIGNAL(error(QString)), this, SLOT(showErrorMessage(QString)));
m_ui->settingsWidget->addSettingsPage(new AgentSettingsPage(m_ui->tabWidget)); m_ui->settingsWidget->addSettingsPage(new AgentSettingsPage(m_ui->tabWidget));
#endif #endif
@ -454,6 +455,11 @@ void MainWindow::showKeePassHTTPDeprecationNotice()
disconnect(m_ui->globalMessageWidget, SIGNAL(hideAnimationFinished()), this, SLOT(showKeePassHTTPDeprecationNotice())); disconnect(m_ui->globalMessageWidget, SIGNAL(hideAnimationFinished()), this, SLOT(showKeePassHTTPDeprecationNotice()));
} }
void MainWindow::showErrorMessage(const QString& message)
{
m_ui->globalMessageWidget->showMessage(message, MessageWidget::Error);
}
void MainWindow::appExit() void MainWindow::appExit()
{ {
m_appExitCalled = true; m_appExitCalled = true;

View file

@ -104,6 +104,7 @@ private slots:
void hideTabMessage(); void hideTabMessage();
void handleScreenLock(); void handleScreenLock();
void showKeePassHTTPDeprecationNotice(); void showKeePassHTTPDeprecationNotice();
void showErrorMessage(const QString& message);
private: private:
static void setShortcut(QAction* action, QKeySequence::StandardKey standard, int fallback = 0); static void setShortcut(QAction* action, QKeySequence::StandardKey standard, int fallback = 0);

View file

@ -485,7 +485,10 @@ void EditEntryWidget::addKeyToAgent()
lifetime = m_sshAgentUi->lifetimeSpinBox->value(); lifetime = m_sshAgentUi->lifetimeSpinBox->value();
} }
SSHAgent::instance()->addIdentity(key, lifetime, confirm); if (!SSHAgent::instance()->addIdentity(key, lifetime, confirm)) {
showMessage(SSHAgent::instance()->errorString(), MessageWidget::Error);
return;
}
if (m_sshAgentUi->removeKeyFromAgentCheckBox->isChecked()) { if (m_sshAgentUi->removeKeyFromAgentCheckBox->isChecked()) {
SSHAgent::instance()->removeIdentityAtLock(key, m_entry->uuid()); SSHAgent::instance()->removeIdentityAtLock(key, m_entry->uuid());
@ -496,8 +499,13 @@ void EditEntryWidget::removeKeyFromAgent()
{ {
OpenSSHKey key; OpenSSHKey key;
if (getOpenSSHKey(key)) { if (!getOpenSSHKey(key)) {
SSHAgent::instance()->removeIdentity(key); return;
}
if (!SSHAgent::instance()->removeIdentity(key)) {
showMessage(SSHAgent::instance()->errorString(), MessageWidget::Error);
return;
} }
} }

View file

@ -58,6 +58,11 @@ void SSHAgent::init(QObject* parent)
m_instance = new SSHAgent(parent); m_instance = new SSHAgent(parent);
} }
const QString SSHAgent::errorString() const
{
return m_error;
}
bool SSHAgent::isAgentRunning() const bool SSHAgent::isAgentRunning() const
{ {
#ifndef Q_OS_WIN #ifndef Q_OS_WIN
@ -67,7 +72,7 @@ bool SSHAgent::isAgentRunning() const
#endif #endif
} }
bool SSHAgent::sendMessage(const QByteArray& in, QByteArray& out) const bool SSHAgent::sendMessage(const QByteArray& in, QByteArray& out)
{ {
#ifndef Q_OS_WIN #ifndef Q_OS_WIN
QLocalSocket socket; QLocalSocket socket;
@ -75,6 +80,7 @@ bool SSHAgent::sendMessage(const QByteArray& in, QByteArray& out) const
socket.connectToServer(m_socketPath); socket.connectToServer(m_socketPath);
if (!socket.waitForConnected(500)) { if (!socket.waitForConnected(500)) {
m_error = tr("Agent connection failed.");
return false; return false;
} }
@ -82,6 +88,7 @@ bool SSHAgent::sendMessage(const QByteArray& in, QByteArray& out) const
stream.flush(); stream.flush();
if (!stream.readString(out)) { if (!stream.readString(out)) {
m_error = tr("Agent protocol error.");
return false; return false;
} }
@ -92,10 +99,12 @@ bool SSHAgent::sendMessage(const QByteArray& in, QByteArray& out) const
HWND hWnd = FindWindowA("Pageant", "Pageant"); HWND hWnd = FindWindowA("Pageant", "Pageant");
if (!hWnd) { if (!hWnd) {
m_error = tr("Agent connection failed.");
return false; return false;
} }
if (static_cast<quint32>(in.length()) > AGENT_MAX_MSGLEN - 4) { if (static_cast<quint32>(in.length()) > AGENT_MAX_MSGLEN - 4) {
m_error = tr("Agent connection failed.");
return false; return false;
} }
@ -104,6 +113,7 @@ bool SSHAgent::sendMessage(const QByteArray& in, QByteArray& out) const
HANDLE handle = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, AGENT_MAX_MSGLEN, mapName.data()); HANDLE handle = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, AGENT_MAX_MSGLEN, mapName.data());
if (!handle) { if (!handle) {
m_error = tr("Agent connection failed.");
return false; return false;
} }
@ -111,6 +121,7 @@ bool SSHAgent::sendMessage(const QByteArray& in, QByteArray& out) const
if (!ptr) { if (!ptr) {
CloseHandle(handle); CloseHandle(handle);
m_error = tr("Agent connection failed.");
return false; return false;
} }
@ -132,7 +143,11 @@ bool SSHAgent::sendMessage(const QByteArray& in, QByteArray& out) const
if (responseLength <= AGENT_MAX_MSGLEN) { if (responseLength <= AGENT_MAX_MSGLEN) {
out.resize(responseLength); out.resize(responseLength);
memcpy(out.data(), requestData, responseLength); memcpy(out.data(), requestData, responseLength);
} else {
m_error = tr("Agent protocol error.");
} }
} else {
m_error = tr("Agent protocol error.");
} }
UnmapViewOfFile(ptr); UnmapViewOfFile(ptr);
@ -143,8 +158,13 @@ bool SSHAgent::sendMessage(const QByteArray& in, QByteArray& out) const
} }
bool SSHAgent::addIdentity(OpenSSHKey& key, quint32 lifetime, bool confirm) const bool SSHAgent::addIdentity(OpenSSHKey& key, quint32 lifetime, bool confirm)
{ {
if (!isAgentRunning()) {
m_error = tr("No agent running, cannot add identity.");
return false;
}
QByteArray requestData; QByteArray requestData;
BinaryStream request(&requestData); BinaryStream request(&requestData);
@ -161,17 +181,25 @@ bool SSHAgent::addIdentity(OpenSSHKey& key, quint32 lifetime, bool confirm) cons
} }
QByteArray responseData; QByteArray responseData;
sendMessage(requestData, responseData); if (!sendMessage(requestData, responseData)) {
return false;
}
if (responseData.length() < 1 || static_cast<quint8>(responseData[0]) != SSH_AGENT_SUCCESS) { if (responseData.length() < 1 || static_cast<quint8>(responseData[0]) != SSH_AGENT_SUCCESS) {
m_error = tr("Agent refused this identity.");
return false; return false;
} }
return true; return true;
} }
bool SSHAgent::removeIdentity(OpenSSHKey& key) const bool SSHAgent::removeIdentity(OpenSSHKey& key)
{ {
if (!isAgentRunning()) {
m_error = tr("No agent running, cannot remove identity.");
return false;
}
QByteArray requestData; QByteArray requestData;
BinaryStream request(&requestData); BinaryStream request(&requestData);
@ -183,9 +211,12 @@ bool SSHAgent::removeIdentity(OpenSSHKey& key) const
request.writeString(keyData); request.writeString(keyData);
QByteArray responseData; QByteArray responseData;
sendMessage(requestData, responseData); if (!sendMessage(requestData, responseData)) {
return false;
}
if (responseData.length() < 1 || static_cast<quint8>(responseData[0]) != SSH_AGENT_SUCCESS) { if (responseData.length() < 1 || static_cast<quint8>(responseData[0]) != SSH_AGENT_SUCCESS) {
m_error = tr("Agent does not have this identity.");
return false; return false;
} }
@ -210,9 +241,12 @@ void SSHAgent::databaseModeChanged(DatabaseWidget::Mode mode)
Uuid uuid = widget->database()->uuid(); Uuid uuid = widget->database()->uuid();
if (mode == DatabaseWidget::LockedMode && m_keys.contains(uuid.toHex())) { if (mode == DatabaseWidget::LockedMode && m_keys.contains(uuid.toHex())) {
QSet<OpenSSHKey> keys = m_keys.take(uuid.toHex()); QSet<OpenSSHKey> keys = m_keys.take(uuid.toHex());
for (OpenSSHKey key : keys) { for (OpenSSHKey key : keys) {
removeIdentity(key); if (!removeIdentity(key)) {
emit error(m_error);
}
} }
} else if (mode == DatabaseWidget::ViewMode && !m_keys.contains(uuid.toHex())) { } else if (mode == DatabaseWidget::ViewMode && !m_keys.contains(uuid.toHex())) {
for (Entry* e : widget->database()->rootGroup()->entriesRecursive()) { for (Entry* e : widget->database()->rootGroup()->entriesRecursive()) {
@ -279,7 +313,9 @@ void SSHAgent::databaseModeChanged(DatabaseWidget::Mode mode)
lifetime = settings.lifetimeConstraintDuration(); lifetime = settings.lifetimeConstraintDuration();
} }
addIdentity(key, lifetime, settings.useConfirmConstraintWhenAdding()); if (!addIdentity(key, lifetime, settings.useConfirmConstraintWhenAdding())) {
emit error(m_error);
}
} }
} }
} }

View file

@ -33,11 +33,15 @@ public:
static SSHAgent* instance(); static SSHAgent* instance();
static void init(QObject* parent); static void init(QObject* parent);
const QString errorString() const;
bool isAgentRunning() const; bool isAgentRunning() const;
bool addIdentity(OpenSSHKey& key, quint32 lifetime = 0, bool confirm = false) const; bool addIdentity(OpenSSHKey& key, quint32 lifetime = 0, bool confirm = false);
bool removeIdentity(OpenSSHKey& key) const; bool removeIdentity(OpenSSHKey& key);
void removeIdentityAtLock(const OpenSSHKey& key, const Uuid& uuid); void removeIdentityAtLock(const OpenSSHKey& key, const Uuid& uuid);
signals:
void error(const QString& message);
public slots: public slots:
void databaseModeChanged(DatabaseWidget::Mode mode = DatabaseWidget::LockedMode); void databaseModeChanged(DatabaseWidget::Mode mode = DatabaseWidget::LockedMode);
@ -56,7 +60,7 @@ private:
explicit SSHAgent(QObject* parent = nullptr); explicit SSHAgent(QObject* parent = nullptr);
~SSHAgent(); ~SSHAgent();
bool sendMessage(const QByteArray& in, QByteArray& out) const; bool sendMessage(const QByteArray& in, QByteArray& out);
static SSHAgent* m_instance; static SSHAgent* m_instance;
@ -68,6 +72,7 @@ private:
#endif #endif
QMap<QString, QSet<OpenSSHKey>> m_keys; QMap<QString, QSet<OpenSSHKey>> m_keys;
QString m_error;
}; };
#endif // AGENTCLIENT_H #endif // AGENTCLIENT_H