Skip to content

Commit

Permalink
ssh: Add support for userauth banner.
Browse files Browse the repository at this point in the history
The new libssh2_userauth_banner API allows to get an optional
userauth banner sent with SSH_MSG_USERAUTH_BANNER packet by the
server.

Closes libssh2#610
  • Loading branch information
snimmagadda authored and bagder committed Jan 13, 2022
1 parent 13ad7b2 commit d5ed0e6
Show file tree
Hide file tree
Showing 7 changed files with 118 additions and 2 deletions.
1 change: 1 addition & 0 deletions docs/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ set(MAN_PAGES
libssh2_trace.3
libssh2_trace_sethandler.3
libssh2_userauth_authenticated.3
libssh2_userauth_banner.3
libssh2_userauth_hostbased_fromfile.3
libssh2_userauth_hostbased_fromfile_ex.3
libssh2_userauth_keyboard_interactive.3
Expand Down
1 change: 1 addition & 0 deletions docs/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ dist_man_MANS = \
libssh2_trace.3 \
libssh2_trace_sethandler.3 \
libssh2_userauth_authenticated.3 \
libssh2_userauth_banner.3 \
libssh2_userauth_hostbased_fromfile.3 \
libssh2_userauth_hostbased_fromfile_ex.3 \
libssh2_userauth_keyboard_interactive.3 \
Expand Down
30 changes: 30 additions & 0 deletions docs/libssh2_userauth_banner.3
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
.TH libssh2_userauth_banner 3 "1 Jun 2021" "libssh2 1.9.0" "libssh2 manual"
.SH NAME
libssh2_userauth_banner - get the server's userauth banner message
.SH SYNOPSIS
.nf
#include <libssh2.h>

int
libssh2_userauth_banner(LIBSSH2_SESSION *session, char **banner);
.SH DESCRIPTION
\fIsession\fP - Session instance as returned by
.BR libssh2_session_init_ex(3)

\fIbanner\fP - Should point to a pointer that gets filled with banner message.

After an authentication has been attempted, such as a
\fBSSH_USERAUTH_NONE\fP request sent by
.BR libssh2_userauth_list(3) ,
this function can be called to retrieve the userauth banner sent by
the server. If no such banner is sent, or if an authentication has not
yet been attempted, returns LIBSSH2_ERROR_MISSING_USERAUTH_BANNER.
.SH RETURN VALUE
On success returns 0 and an UTF-8 NUL-terminated string is stored in the
\fIbanner\fP. This string is internally managed by libssh2 and will be
deallocated upon session termination.
On failure returns
LIBSSH2_ERROR_MISSING_USERAUTH_BANNER.
.SH SEE ALSO
.BR libssh2_session_init_ex(3),
.BR libssh2_userauth_list(3)
3 changes: 3 additions & 0 deletions include/libssh2.h
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,7 @@ typedef struct _LIBSSH2_POLLFD {
#define LIBSSH2_ERROR_CHANNEL_WINDOW_FULL -47
#define LIBSSH2_ERROR_KEYFILE_AUTH_FAILED -48
#define LIBSSH2_ERROR_RANDGEN -49
#define LIBSSH2_ERROR_MISSING_USERAUTH_BANNER -50

/* this is a define to provide the old (<= 1.2.7) name */
#define LIBSSH2_ERROR_BANNER_NONE LIBSSH2_ERROR_BANNER_RECV
Expand Down Expand Up @@ -615,6 +616,8 @@ LIBSSH2_API const char *libssh2_session_banner_get(LIBSSH2_SESSION *session);
LIBSSH2_API char *libssh2_userauth_list(LIBSSH2_SESSION *session,
const char *username,
unsigned int username_len);
LIBSSH2_API int libssh2_userauth_banner(LIBSSH2_SESSION *session,
char **banner);
LIBSSH2_API int libssh2_userauth_authenticated(LIBSSH2_SESSION *session);

LIBSSH2_API int
Expand Down
1 change: 1 addition & 0 deletions src/libssh2_priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -720,6 +720,7 @@ struct _LIBSSH2_SESSION
libssh2_nonblocking_states userauth_list_state;
unsigned char *userauth_list_data;
size_t userauth_list_data_len;
char *userauth_banner;
packet_requirev_state_t userauth_list_packet_requirev_state;

/* State variables used in libssh2_userauth_password_ex() */
Expand Down
3 changes: 3 additions & 0 deletions src/session.c
Original file line number Diff line number Diff line change
Expand Up @@ -994,6 +994,9 @@ session_free(LIBSSH2_SESSION *session)
if(session->userauth_list_data) {
LIBSSH2_FREE(session, session->userauth_list_data);
}
if(session->userauth_banner) {
LIBSSH2_FREE(session, session->userauth_banner);
}
if(session->userauth_pswd_data) {
LIBSSH2_FREE(session, session->userauth_pswd_data);
}
Expand Down
81 changes: 79 additions & 2 deletions src/userauth.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,13 @@
static char *userauth_list(LIBSSH2_SESSION *session, const char *username,
unsigned int username_len)
{
static const unsigned char reply_codes[3] =
{ SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, 0 };
unsigned char reply_codes[4] =
{ SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE,
SSH_MSG_USERAUTH_BANNER, 0 };
/* packet_type(1) + username_len(4) + service_len(4) +
service(14)"ssh-connection" + method_len(4) = 27 */
unsigned long methods_len;
unsigned int banner_len;
unsigned char *s;
int rc;

Expand Down Expand Up @@ -134,6 +136,57 @@ static char *userauth_list(LIBSSH2_SESSION *session, const char *username,
return NULL;
}

if(session->userauth_list_data[0] == SSH_MSG_USERAUTH_BANNER) {
if(session->userauth_list_data_len < 5) {
LIBSSH2_FREE(session, session->userauth_list_data);
session->userauth_list_data = NULL;
_libssh2_error(session, LIBSSH2_ERROR_PROTO,
"Unexpected packet size");
return NULL;
}
banner_len = _libssh2_ntohu32(session->userauth_list_data + 1);
if(banner_len >= session->userauth_list_data_len - 5) {
LIBSSH2_FREE(session, session->userauth_list_data);
session->userauth_list_data = NULL;
_libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY,
"Unexpected userauth banner size");
return NULL;
}
session->userauth_banner = LIBSSH2_ALLOC(session, banner_len);
if(!session->userauth_banner) {
LIBSSH2_FREE(session, session->userauth_list_data);
session->userauth_list_data = NULL;
_libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate memory for userauth_banner");
return NULL;
}
memmove(session->userauth_banner, session->userauth_list_data + 5,
banner_len);
session->userauth_banner[banner_len] = '\0';
_libssh2_debug(session, LIBSSH2_TRACE_AUTH,
"Banner: %s",
session->userauth_banner);
LIBSSH2_FREE(session, session->userauth_list_data);
session->userauth_list_data = NULL;
/* SSH_MSG_USERAUTH_BANNER has been handled */
reply_codes[2] = 0;
rc = _libssh2_packet_requirev(session, reply_codes,
&session->userauth_list_data,
&session->userauth_list_data_len, 0,
NULL, 0,
&session->userauth_list_packet_requirev_state);
if(rc == LIBSSH2_ERROR_EAGAIN) {
_libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
"Would block requesting userauth list");
return NULL;
}
else if(rc || (session->userauth_list_data_len < 1)) {
_libssh2_error(session, rc, "Failed getting response");
session->userauth_list_state = libssh2_NB_state_idle;
return NULL;
}
}

if(session->userauth_list_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
/* Wow, who'dve thought... */
_libssh2_error(session, LIBSSH2_ERROR_NONE, "No error");
Expand Down Expand Up @@ -189,6 +242,30 @@ libssh2_userauth_list(LIBSSH2_SESSION * session, const char *user,
return ptr;
}

/* libssh2_userauth_banner
*
* Retrieve banner message from server, if available.
* When no such message is sent by server or if no authentication attempt has
* been made, this function returns LIBSSH2_ERROR_MISSING_AUTH_BANNER.
*/
LIBSSH2_API int
libssh2_userauth_banner(LIBSSH2_SESSION *session, char **banner)
{
if(NULL == session)
return LIBSSH2_ERROR_MISSING_USERAUTH_BANNER;

if(!session->userauth_banner) {
return _libssh2_error(session,
LIBSSH2_ERROR_MISSING_USERAUTH_BANNER,
"Missing userauth banner");
}

if(banner != NULL)
*banner = session->userauth_banner;

return LIBSSH2_ERROR_NONE;
}

/*
* libssh2_userauth_authenticated
*
Expand Down

0 comments on commit d5ed0e6

Please sign in to comment.