From 90b1f5bfff754b7190df6e59882e3b74869b2a92 Mon Sep 17 00:00:00 2001
From: Dave McCaldon <dave@mccaldon.com>
Date: Wed, 20 Jan 2010 16:07:22 -0500
Subject: [PATCH 2/2] Handle SSH_MSG_USERAUTH_FAILURE for password and kbd-int authentication

Neither of libssh2_userauth_password_ex() or libssh2_userauth_keyboard_interactive_ex() would return a login failure error if the server responded with a SSH_MSG_USERAUTH_FAILURE, you would see whatever previous error had occurred, typically LIBSSH2_ERROR_EAGAIN.

This patch changes error code -18 to LIBSSH2_ERROR_AUTHENTICATION_FAILED and makes LIBSSH2_ERROR_PUBLICKEY_UNRECOGNIZED an alias for LIBSSH2_ERROR_AUTHENTICATION_FAILED.  In addition, new logic in userauth_password() properly handles SSH_MSG_USERAUTH_FAILURE and both this function and userauth_keyboard_interactive() now properly return LIBSSH2_ERROR_AUTHENTICATION_FAILED.
---
 docs/libssh2_userauth_keyboard_interactive_ex.3 |    2 ++
 docs/libssh2_userauth_password_ex.3             |    2 ++
 include/libssh2.h                               |    3 ++-
 src/userauth.c                                  |   17 +++++++++++++++++
 4 files changed, 23 insertions(+), 1 deletions(-)

diff --git a/docs/libssh2_userauth_keyboard_interactive_ex.3 b/docs/libssh2_userauth_keyboard_interactive_ex.3
index 80572ae..c70b4ab 100644
--- a/docs/libssh2_userauth_keyboard_interactive_ex.3
+++ b/docs/libssh2_userauth_keyboard_interactive_ex.3
@@ -39,5 +39,7 @@ LIBSSH2_ERROR_EAGAIN is a negative number, it isn't really a failure per se.
 
 \fILIBSSH2_ERROR_SOCKET_SEND\fP - Unable to send data on socket.
 
+\fLIBSSH2_ERROR_AUTHENTICATION_FAILED\fP -  failed, invalid username/password or public/private key.
+
 .SH SEE ALSO
 .BR libssh2_session_init_ex(3)
diff --git a/docs/libssh2_userauth_password_ex.3 b/docs/libssh2_userauth_password_ex.3
index 79a471f..a18d3c4 100644
--- a/docs/libssh2_userauth_password_ex.3
+++ b/docs/libssh2_userauth_password_ex.3
@@ -46,5 +46,7 @@ LIBSSH2_ERROR_EAGAIN is a negative number, it isn't really a failure per se.
 
 \fILIBSSH2_ERROR_PASSWORD_EXPIRED\fP - 
 
+\fLIBSSH2_ERROR_AUTHENTICATION_FAILED\fP -  failed, invalid username/password or public/private key.
+
 .SH SEE ALSO
 .BR libssh2_session_init_ex(3)
diff --git a/include/libssh2.h b/include/libssh2.h
index 890749e..91b51cc 100644
--- a/include/libssh2.h
+++ b/include/libssh2.h
@@ -341,7 +341,8 @@ typedef struct _LIBSSH2_POLLFD {
 #define LIBSSH2_ERROR_PASSWORD_EXPIRED          -15
 #define LIBSSH2_ERROR_FILE                      -16
 #define LIBSSH2_ERROR_METHOD_NONE               -17
-#define LIBSSH2_ERROR_PUBLICKEY_UNRECOGNIZED    -18
+#define LIBSSH2_ERROR_AUTHENTICATION_FAILED     -18
+#define LIBSSH2_ERROR_PUBLICKEY_UNRECOGNIZED    LIBSSH2_ERROR_AUTHENTICATION_FAILED
 #define LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED      -19
 #define LIBSSH2_ERROR_CHANNEL_OUTOFORDER        -20
 #define LIBSSH2_ERROR_CHANNEL_FAILURE           -21
diff --git a/src/userauth.c b/src/userauth.c
index ee7fee9..2bb84bc 100644
--- a/src/userauth.c
+++ b/src/userauth.c
@@ -310,6 +310,17 @@ userauth_password(LIBSSH2_SESSION *session, const char *username,
                 session->state |= LIBSSH2_STATE_AUTHENTICATED;
                 session->userauth_pswd_state = libssh2_NB_state_idle;
                 return 0;
+            } else if (session->userauth_pswd_data[0] == SSH_MSG_USERAUTH_FAILURE) {
+                _libssh2_debug(session, LIBSSH2_TRACE_AUTH,
+                               "Password authentication failed");
+                LIBSSH2_FREE(session, session->userauth_pswd_data);
+                session->userauth_pswd_data = NULL;
+                session->userauth_pswd_state = libssh2_NB_state_idle;
+                libssh2_error(session,
+                              LIBSSH2_ERROR_AUTHENTICATION_FAILED,
+                              "Authentication failed (username/password)",
+                              0);
+                return -1;
             }
 
             session->userauth_pswd_newpw = NULL;
@@ -1473,9 +1484,15 @@ userauth_keyboard_interactive(LIBSSH2_SESSION * session,
             }
 
             if (session->userauth_kybd_data[0] == SSH_MSG_USERAUTH_FAILURE) {
+                _libssh2_debug(session, LIBSSH2_TRACE_AUTH,
+                               "Keyboard-interactive authentication failed");
                 LIBSSH2_FREE(session, session->userauth_kybd_data);
                 session->userauth_kybd_data = NULL;
                 session->userauth_kybd_state = libssh2_NB_state_idle;
+                libssh2_error(session,
+                              LIBSSH2_ERROR_AUTHENTICATION_FAILED,
+                              "Authentication failed (keyboard-interactive)",
+                              0);
                 return -1;
             }
 
-- 
1.6.4.4


