[plasma/ksshaskpass] /: Consider password incorrect when same SSH process asks the same prompt again
Kai Uwe Broulik <[email protected]>
| Newsgroups | gmane.comp.kde.cvs |
|---|---|
| Message-ID | <[email protected]> |
Git commit b438fa055c55bc3eb967229578263ca889c9f493 by Kai Uwe Broulik.
Committed on 19/08/2026 at 10:57.
Pushed by broulik into branch 'master'.
Consider password incorrect when same SSH process asks the same prompt again
There's no real way for ksshaskpass to know when the password was rejected,
all it gets is the "user@host's password: " (or similar) prompt.
Therefore, remember the last prompt and PID of the ssh process and when the
same is encountered again, consider the stored password incorrect and bring
up the prompt again. This avoids having a wrong password (or when it changes
and is no longer correct) lock you out unless you manually remove the password
from the keystore again.
M +1 -0 .kde-ci.yml
M +1 -0 CMakeLists.txt
M +1 -0 src/CMakeLists.txt
M +25 -1 src/main.cpp
https://invent.kde.org/plasma/ksshaskpass/-/commit/b438fa055c55bc3eb967229578263ca889c9f493
diff --git a/.kde-ci.yml b/.kde-ci.yml
index ae4e8b7..fb0ad9c 100644
--- a/.kde-ci.yml
+++ b/.kde-ci.yml
@@ -5,6 +5,7 @@ Dependencies:
- 'on': ['@all']
'require':
'frameworks/extra-cmake-modules': '@latest-kf6'
+ 'frameworks/kconfig': '@latest-kf6'
'frameworks/kcoreaddons': '@latest-kf6'
'frameworks/ki18n': '@latest-kf6'
'third-party/qtkeychain': '@latest'
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 515e84c..779c3a0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -37,6 +37,7 @@ find_package(Qt6Keychain ${QT_KEYCHAIN_MIN_VERSION} REQUIRED)
add_definitions(-DQT_NO_NARROWING_CONVERSIONS_IN_CONNECT)
find_package(KF6 ${KF6_MIN_VERSION} REQUIRED COMPONENTS
+ Config
CoreAddons
I18n
WidgetsAddons
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 22a7f85..d5160e3 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -18,6 +18,7 @@ target_link_libraries(ksshaskpass_prompt PUBLIC Qt6::Core)
add_executable(ksshaskpass main.cpp)
target_compile_definitions(ksshaskpass PRIVATE -DPROJECT_VERSION="${PROJECT_VERSION}")
target_link_libraries(ksshaskpass
+ KF6::ConfigCore
KF6::CoreAddons
KF6::I18n
KF6::WidgetsAddons
diff --git a/src/main.cpp b/src/main.cpp
index 088b0a2..245bf2b 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -6,11 +6,14 @@
#include <memory>
#include <sys/resource.h>
+#include <unistd.h>
#include <KAboutData>
+#include <KConfigGroup>
#include <KLocalizedString>
#include <KMessageBox>
#include <KPasswordDialog>
+#include <KSharedConfig>
#include <QApplication>
#include <QCommandLineParser>
@@ -95,6 +98,7 @@ int main(int argc, char **argv)
QString item;
bool ignoreKeychain = false;
DisplayType displayType = DisplayType::Password;
+ bool askAgain = false;
// Parse commandline arguments
if (!parser.positionalArguments().isEmpty()) {
@@ -102,6 +106,9 @@ int main(int argc, char **argv)
parsePrompt(promptType, dialog, identifier, ignoreKeychain, displayType);
}
+ auto cfg = KSharedConfig::openStateConfig();
+ KConfigGroup grp(cfg, QStringLiteral("Last Prompt"));
+
if ((!ignoreKeychain) && (!identifier.isNull())) {
QKeychain::ReadPasswordJob job(app.applicationName());
job.setKey(identifier);
@@ -138,9 +145,18 @@ int main(int argc, char **argv)
}
}
}
+
+ if (!item.isEmpty() && grp.readEntry("PID", pid_t{-1}) == getppid() && grp.readEntry("Prompt", QString()) == dialog) {
+ qCInfo(LOG_KSSHASKPASS) << "SSH process" << getppid() << "asked for same prompt already, assuming stored password is incorrect";
+ askAgain = true;
+ }
}
- if (!item.isEmpty()) {
+ grp.deleteGroup();
+
+ if (!askAgain && !item.isEmpty()) {
+ grp.writeEntry("PID", getppid());
+ grp.writeEntry("Prompt", dialog);
QTextStream(stdout) << item;
return 0;
}
@@ -219,6 +235,11 @@ int main(int argc, char **argv)
ui.passwordLabel->hide();
}
+ if (!item.isEmpty()) {
+ ui.lineEdit->setPassword(item);
+ ui.keepCheckBox->setChecked(true);
+ }
+
if (dlg.exec() == QDialog::Accepted) {
item = ui.lineEdit->password();
remember = ui.keepCheckBox->isChecked();
@@ -232,6 +253,9 @@ int main(int argc, char **argv)
if (!identifier.isEmpty() && remember.has_value()) {
if (remember.value()) {
+ grp.writeEntry("PID", getppid());
+ grp.writeEntry("Prompt", dialog);
+
QKeychain::WritePasswordJob job(app.applicationName());
job.setKey(identifier);
job.setTextData(item);