From 2f6193a8c5c07e238fb8347aa75522cc5f6029e7 Mon Sep 17 00:00:00 2001
From: Dave McCaldon <dave@mccaldon.com>
Date: Wed, 20 Jan 2010 16:07:22 -0500
Subject: [PATCH 4/4] 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 ++
 docs/libssh2_userauth_publickey_fromfile_ex.3   |    2 +-
 include/libssh2.h                               |    3 ++-
 src/userauth.c                                  |   19 ++++++++++++++++++-
 5 files changed, 25 insertions(+), 3 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/docs/libssh2_userauth_publickey_fromfile_ex.3 b/docs/libssh2_userauth_publickey_fromfile_ex.3
index 0e21e92..6c7b7cf 100644
--- a/docs/libssh2_userauth_publickey_fromfile_ex.3
+++ b/docs/libssh2_userauth_publickey_fromfile_ex.3
@@ -40,7 +40,7 @@ LIBSSH2_ERROR_EAGAIN is a negative number, it isn't really a failure per se.
 
 \fILIBSSH2_ERROR_SOCKET_TIMEOUT\fP - 
 
-\fILIBSSH2_ERROR_PUBLICKEY_UNRECOGNIZED\fP - >The username/public key 
+\fILIBSSH2_ERROR_AUTHENTICATION_FAILED\fP - >The username/public key 
 combination was invalid.
 
 \fILIBSSH2_ERROR_PUBLICKEY_UNVERIFIED\fP - The username/public key 
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..e860fd7 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;
@@ -1100,7 +1111,7 @@ userauth_publickey(LIBSSH2_SESSION *session,
             session->userauth_pblc_packet = NULL;
             LIBSSH2_FREE(session, session->userauth_pblc_method);
             session->userauth_pblc_method = NULL;
-            libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNRECOGNIZED,
+            libssh2_error(session, LIBSSH2_ERROR_AUTHENTICATION_FAILED,
                           "Username/PublicKey combination invalid", 0);
             session->userauth_pblc_state = libssh2_NB_state_idle;
             return -1;
@@ -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


