From 6a83476831dcd31cd29ff54100d9158aeb43a9f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zolt=C3=A1n=20Papp?= Date: Tue, 11 Aug 2026 16:40:12 +0200 Subject: [PATCH] [android] stop prompting for a password the server will not take Any authentication failure on a regular server returned the password-required marker, so against a server with password authentication disabled the client asked again after every attempt and reported each one as a wrong password. gossh only lists a method under "attempted methods" when the server offered it. When a supplied password never got attempted, surface the real error instead of the marker, the same way the desktop client reports it. A first connect without a password still prompts. --- client/android/ssh_client.go | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/client/android/ssh_client.go b/client/android/ssh_client.go index 3ee81d624..f57a8f056 100644 --- a/client/android/ssh_client.go +++ b/client/android/ssh_client.go @@ -151,7 +151,8 @@ func (s *SSHClient) Connect(host string, port int, user, password string) error // one instead of failing. NetBird servers never use a password, so a // failure there is genuine. if err != nil && serverType != detection.ServerTypeNetBirdJWT && - serverType != detection.ServerTypeNetBirdNoJWT && isAuthFailure(err) { + serverType != detection.ServerTypeNetBirdNoJWT && isAuthFailure(err) && + passwordCouldHelp(err, password != "") { return errPasswordRequired } if err != nil { @@ -173,6 +174,18 @@ func isAuthFailure(err error) bool { return strings.Contains(err.Error(), "unable to authenticate") } +// passwordCouldHelp reports whether prompting for a password again can change +// the outcome. gossh lists a method under "attempted methods" only when the +// server offered it, so a supplied password that was never attempted means the +// server does not accept passwords and the real error should surface instead. +func passwordCouldHelp(err error, passwordOffered bool) bool { + if !passwordOffered { + return true + } + msg := err.Error() + return strings.Contains(msg, "password") || strings.Contains(msg, "keyboard-interactive") +} + // StartSession requests a PTY and starts an interactive shell. Output from // the session is forwarded to the listener via OnData. func (s *SSHClient) StartSession(cols, rows int) error {