mirror of
https://github.com/libssh2/libssh2.git
synced 2025-07-31 00:03:08 +03:00
Use modern API in userauth_keyboard_interactive() (#663)
Files: userauth_kbd_packet.c, userauth_kbd_packet.h, test_keyboard_interactive_auth_info_request.c, userauth.c Notes: This refactors `SSH_MSG_USERAUTH_INFO_REQUEST` processing in `userauth_keyboard_interactive()` in order to improve robustness, correctness and readability or the code. * Refactor userauth_keyboard_interactive to use new api for packet parsing * add unit test for userauth_keyboard_interactive_parse_response() * add _libssh2_get_boolean() and _libssh2_get_byte() utility functions Credit: xalopp
This commit is contained in:
@ -1,5 +1,6 @@
|
|||||||
CSOURCES = channel.c comp.c crypt.c hostkey.c kex.c mac.c misc.c \
|
CSOURCES = channel.c comp.c crypt.c hostkey.c kex.c mac.c misc.c \
|
||||||
packet.c publickey.c scp.c session.c sftp.c userauth.c transport.c \
|
packet.c publickey.c scp.c session.c sftp.c userauth.c transport.c \
|
||||||
|
userauth_kbd_packet.c \
|
||||||
version.c knownhost.c agent.c $(CRYPTO_CSOURCES) pem.c keepalive.c global.c \
|
version.c knownhost.c agent.c $(CRYPTO_CSOURCES) pem.c keepalive.c global.c \
|
||||||
blowfish.c bcrypt_pbkdf.c agent_win.c
|
blowfish.c bcrypt_pbkdf.c agent_win.c
|
||||||
|
|
||||||
|
@ -272,8 +272,8 @@ typedef off_t libssh2_struct_stat_size;
|
|||||||
|
|
||||||
typedef struct _LIBSSH2_USERAUTH_KBDINT_PROMPT
|
typedef struct _LIBSSH2_USERAUTH_KBDINT_PROMPT
|
||||||
{
|
{
|
||||||
char *text;
|
unsigned char *text;
|
||||||
unsigned int length;
|
size_t length;
|
||||||
unsigned char echo;
|
unsigned char echo;
|
||||||
} LIBSSH2_USERAUTH_KBDINT_PROMPT;
|
} LIBSSH2_USERAUTH_KBDINT_PROMPT;
|
||||||
|
|
||||||
|
@ -207,6 +207,8 @@ set(SOURCES
|
|||||||
sftp.h
|
sftp.h
|
||||||
transport.c
|
transport.c
|
||||||
transport.h
|
transport.h
|
||||||
|
userauth_kbd_packet.c
|
||||||
|
userauth_kbd_packet.h
|
||||||
userauth.c
|
userauth.c
|
||||||
userauth.h
|
userauth.h
|
||||||
version.c)
|
version.c)
|
||||||
|
@ -760,10 +760,10 @@ struct _LIBSSH2_SESSION
|
|||||||
size_t userauth_kybd_data_len;
|
size_t userauth_kybd_data_len;
|
||||||
unsigned char *userauth_kybd_packet;
|
unsigned char *userauth_kybd_packet;
|
||||||
size_t userauth_kybd_packet_len;
|
size_t userauth_kybd_packet_len;
|
||||||
unsigned int userauth_kybd_auth_name_len;
|
size_t userauth_kybd_auth_name_len;
|
||||||
char *userauth_kybd_auth_name;
|
unsigned char *userauth_kybd_auth_name;
|
||||||
unsigned userauth_kybd_auth_instruction_len;
|
size_t userauth_kybd_auth_instruction_len;
|
||||||
char *userauth_kybd_auth_instruction;
|
unsigned char *userauth_kybd_auth_instruction;
|
||||||
unsigned int userauth_kybd_num_prompts;
|
unsigned int userauth_kybd_num_prompts;
|
||||||
int userauth_kybd_auth_failure;
|
int userauth_kybd_auth_failure;
|
||||||
LIBSSH2_USERAUTH_KBDINT_PROMPT *userauth_kybd_prompts;
|
LIBSSH2_USERAUTH_KBDINT_PROMPT *userauth_kybd_prompts;
|
||||||
|
23
src/misc.c
23
src/misc.c
@ -732,6 +732,29 @@ void _libssh2_string_buf_free(LIBSSH2_SESSION *session, struct string_buf *buf)
|
|||||||
buf = NULL;
|
buf = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int _libssh2_get_byte(struct string_buf *buf, unsigned char *out)
|
||||||
|
{
|
||||||
|
if(!_libssh2_check_length(buf, 1)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*out = buf->dataptr[0];
|
||||||
|
buf->dataptr += 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _libssh2_get_boolean(struct string_buf *buf, unsigned char *out)
|
||||||
|
{
|
||||||
|
if(!_libssh2_check_length(buf, 1)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
*out = buf->dataptr[0] == 0 ? 0 : 1;
|
||||||
|
buf->dataptr += 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int _libssh2_get_u32(struct string_buf *buf, uint32_t *out)
|
int _libssh2_get_u32(struct string_buf *buf, uint32_t *out)
|
||||||
{
|
{
|
||||||
if(!_libssh2_check_length(buf, 4)) {
|
if(!_libssh2_check_length(buf, 4)) {
|
||||||
|
@ -91,6 +91,8 @@ void _libssh2_explicit_zero(void *buf, size_t size);
|
|||||||
struct string_buf* _libssh2_string_buf_new(LIBSSH2_SESSION *session);
|
struct string_buf* _libssh2_string_buf_new(LIBSSH2_SESSION *session);
|
||||||
void _libssh2_string_buf_free(LIBSSH2_SESSION *session,
|
void _libssh2_string_buf_free(LIBSSH2_SESSION *session,
|
||||||
struct string_buf *buf);
|
struct string_buf *buf);
|
||||||
|
int _libssh2_get_boolean(struct string_buf *buf, unsigned char *out);
|
||||||
|
int _libssh2_get_byte(struct string_buf *buf, unsigned char *out);
|
||||||
int _libssh2_get_u32(struct string_buf *buf, uint32_t *out);
|
int _libssh2_get_u32(struct string_buf *buf, uint32_t *out);
|
||||||
int _libssh2_get_u64(struct string_buf *buf, libssh2_uint64_t *out);
|
int _libssh2_get_u64(struct string_buf *buf, libssh2_uint64_t *out);
|
||||||
int _libssh2_match_string(struct string_buf *buf, const char *match);
|
int _libssh2_match_string(struct string_buf *buf, const char *match);
|
||||||
|
212
src/userauth.c
212
src/userauth.c
@ -52,6 +52,7 @@
|
|||||||
#include "transport.h"
|
#include "transport.h"
|
||||||
#include "session.h"
|
#include "session.h"
|
||||||
#include "userauth.h"
|
#include "userauth.h"
|
||||||
|
#include "userauth_kbd_packet.h"
|
||||||
|
|
||||||
/* libssh2_userauth_list
|
/* libssh2_userauth_list
|
||||||
*
|
*
|
||||||
@ -1878,13 +1879,13 @@ userauth_keyboard_interactive(LIBSSH2_SESSION * session,
|
|||||||
((*response_callback)))
|
((*response_callback)))
|
||||||
{
|
{
|
||||||
unsigned char *s;
|
unsigned char *s;
|
||||||
|
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
static const unsigned char reply_codes[4] = {
|
static const unsigned char reply_codes[4] = {
|
||||||
SSH_MSG_USERAUTH_SUCCESS,
|
SSH_MSG_USERAUTH_SUCCESS,
|
||||||
SSH_MSG_USERAUTH_FAILURE, SSH_MSG_USERAUTH_INFO_REQUEST, 0
|
SSH_MSG_USERAUTH_FAILURE, SSH_MSG_USERAUTH_INFO_REQUEST, 0
|
||||||
};
|
};
|
||||||
unsigned int language_tag_len;
|
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
if(session->userauth_kybd_state == libssh2_NB_state_idle) {
|
if(session->userauth_kybd_state == libssh2_NB_state_idle) {
|
||||||
@ -2007,215 +2008,14 @@ userauth_keyboard_interactive(LIBSSH2_SESSION * session,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* server requested PAM-like conversation */
|
/* server requested PAM-like conversation */
|
||||||
s = session->userauth_kybd_data + 1;
|
if(userauth_keyboard_interactive_decode_info_request(session)
|
||||||
|
< 0) {
|
||||||
if(session->userauth_kybd_data_len >= 5) {
|
|
||||||
/* string name (ISO-10646 UTF-8) */
|
|
||||||
session->userauth_kybd_auth_name_len = _libssh2_ntohu32(s);
|
|
||||||
if(session->userauth_kybd_auth_name_len >
|
|
||||||
session->userauth_kybd_data_len - 5)
|
|
||||||
return _libssh2_error(session,
|
|
||||||
LIBSSH2_ERROR_OUT_OF_BOUNDARY,
|
|
||||||
"Bad keyboard auth name");
|
|
||||||
s += 4;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
_libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL,
|
|
||||||
"userauth keyboard data buffer too small"
|
|
||||||
"to get length");
|
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(session->userauth_kybd_auth_name_len) {
|
response_callback((const char *)session->userauth_kybd_auth_name,
|
||||||
session->userauth_kybd_auth_name =
|
|
||||||
LIBSSH2_ALLOC(session,
|
|
||||||
session->userauth_kybd_auth_name_len);
|
|
||||||
if(!session->userauth_kybd_auth_name) {
|
|
||||||
_libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
|
||||||
"Unable to allocate memory for "
|
|
||||||
"keyboard-interactive 'name' "
|
|
||||||
"request field");
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
if(s + session->userauth_kybd_auth_name_len <=
|
|
||||||
session->userauth_kybd_data +
|
|
||||||
session->userauth_kybd_data_len) {
|
|
||||||
memcpy(session->userauth_kybd_auth_name, s,
|
|
||||||
session->userauth_kybd_auth_name_len);
|
|
||||||
s += session->userauth_kybd_auth_name_len;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
_libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL,
|
|
||||||
"userauth keyboard data buffer too small"
|
|
||||||
"for auth name");
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(s + 4 <= session->userauth_kybd_data +
|
|
||||||
session->userauth_kybd_data_len) {
|
|
||||||
/* string instruction (ISO-10646 UTF-8) */
|
|
||||||
session->userauth_kybd_auth_instruction_len =
|
|
||||||
_libssh2_ntohu32(s);
|
|
||||||
s += 4;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
_libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL,
|
|
||||||
"userauth keyboard data buffer too small"
|
|
||||||
"for auth instruction length");
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(session->userauth_kybd_auth_instruction_len) {
|
|
||||||
session->userauth_kybd_auth_instruction =
|
|
||||||
LIBSSH2_ALLOC(session,
|
|
||||||
session->userauth_kybd_auth_instruction_len);
|
|
||||||
if(!session->userauth_kybd_auth_instruction) {
|
|
||||||
_libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
|
||||||
"Unable to allocate memory for "
|
|
||||||
"keyboard-interactive 'instruction' "
|
|
||||||
"request field");
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
if(s + session->userauth_kybd_auth_instruction_len <=
|
|
||||||
session->userauth_kybd_data +
|
|
||||||
session->userauth_kybd_data_len) {
|
|
||||||
memcpy(session->userauth_kybd_auth_instruction, s,
|
|
||||||
session->userauth_kybd_auth_instruction_len);
|
|
||||||
s += session->userauth_kybd_auth_instruction_len;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
_libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL,
|
|
||||||
"userauth keyboard data buffer too small"
|
|
||||||
"for auth instruction");
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(s + 4 <= session->userauth_kybd_data +
|
|
||||||
session->userauth_kybd_data_len) {
|
|
||||||
/* string language tag (as defined in [RFC-3066]) */
|
|
||||||
language_tag_len = _libssh2_ntohu32(s);
|
|
||||||
s += 4;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
_libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL,
|
|
||||||
"userauth keyboard data buffer too small"
|
|
||||||
"for auth language tag length");
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(s + language_tag_len <= session->userauth_kybd_data +
|
|
||||||
session->userauth_kybd_data_len) {
|
|
||||||
/* ignoring this field as deprecated */
|
|
||||||
s += language_tag_len;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
_libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL,
|
|
||||||
"userauth keyboard data buffer too small"
|
|
||||||
"for auth language tag");
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(s + 4 <= session->userauth_kybd_data +
|
|
||||||
session->userauth_kybd_data_len) {
|
|
||||||
/* int num-prompts */
|
|
||||||
session->userauth_kybd_num_prompts = _libssh2_ntohu32(s);
|
|
||||||
s += 4;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
_libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL,
|
|
||||||
"userauth keyboard data buffer too small"
|
|
||||||
"for auth num keyboard prompts");
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(session->userauth_kybd_num_prompts > 100) {
|
|
||||||
_libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY,
|
|
||||||
"Too many replies for "
|
|
||||||
"keyboard-interactive prompts");
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(session->userauth_kybd_num_prompts) {
|
|
||||||
session->userauth_kybd_prompts =
|
|
||||||
LIBSSH2_CALLOC(session,
|
|
||||||
sizeof(LIBSSH2_USERAUTH_KBDINT_PROMPT) *
|
|
||||||
session->userauth_kybd_num_prompts);
|
|
||||||
if(!session->userauth_kybd_prompts) {
|
|
||||||
_libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
|
||||||
"Unable to allocate memory for "
|
|
||||||
"keyboard-interactive prompts array");
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
session->userauth_kybd_responses =
|
|
||||||
LIBSSH2_CALLOC(session,
|
|
||||||
sizeof(LIBSSH2_USERAUTH_KBDINT_RESPONSE) *
|
|
||||||
session->userauth_kybd_num_prompts);
|
|
||||||
if(!session->userauth_kybd_responses) {
|
|
||||||
_libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
|
||||||
"Unable to allocate memory for "
|
|
||||||
"keyboard-interactive responses array");
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(i = 0; i < session->userauth_kybd_num_prompts; i++) {
|
|
||||||
if(s + 4 <= session->userauth_kybd_data +
|
|
||||||
session->userauth_kybd_data_len) {
|
|
||||||
/* string prompt[1] (ISO-10646 UTF-8) */
|
|
||||||
session->userauth_kybd_prompts[i].length =
|
|
||||||
_libssh2_ntohu32(s);
|
|
||||||
s += 4;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
_libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL,
|
|
||||||
"userauth keyboard data buffer too "
|
|
||||||
"small for auth keyboard "
|
|
||||||
"prompt length");
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
session->userauth_kybd_prompts[i].text =
|
|
||||||
LIBSSH2_CALLOC(session,
|
|
||||||
session->userauth_kybd_prompts[i].
|
|
||||||
length);
|
|
||||||
if(!session->userauth_kybd_prompts[i].text) {
|
|
||||||
_libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
|
||||||
"Unable to allocate memory for "
|
|
||||||
"keyboard-interactive prompt message");
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(s + session->userauth_kybd_prompts[i].length <=
|
|
||||||
session->userauth_kybd_data +
|
|
||||||
session->userauth_kybd_data_len) {
|
|
||||||
memcpy(session->userauth_kybd_prompts[i].text, s,
|
|
||||||
session->userauth_kybd_prompts[i].length);
|
|
||||||
s += session->userauth_kybd_prompts[i].length;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
_libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL,
|
|
||||||
"userauth keyboard data buffer too "
|
|
||||||
"small for auth keyboard prompt");
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
if(s < session->userauth_kybd_data +
|
|
||||||
session->userauth_kybd_data_len) {
|
|
||||||
/* boolean echo[1] */
|
|
||||||
session->userauth_kybd_prompts[i].echo = *s++;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
_libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL,
|
|
||||||
"userauth keyboard data buffer too "
|
|
||||||
"small for auth keyboard prompt echo");
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
response_callback(session->userauth_kybd_auth_name,
|
|
||||||
session->userauth_kybd_auth_name_len,
|
session->userauth_kybd_auth_name_len,
|
||||||
|
(const char *)
|
||||||
session->userauth_kybd_auth_instruction,
|
session->userauth_kybd_auth_instruction,
|
||||||
session->userauth_kybd_auth_instruction_len,
|
session->userauth_kybd_auth_instruction_len,
|
||||||
session->userauth_kybd_num_prompts,
|
session->userauth_kybd_num_prompts,
|
||||||
|
162
src/userauth_kbd_packet.c
Normal file
162
src/userauth_kbd_packet.c
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
/* Copyright (c) 2022, Xaver Loppenstedt <xaver@loppenstedt.de>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms,
|
||||||
|
* with or without modification, are permitted provided
|
||||||
|
* that the following conditions are met:
|
||||||
|
*
|
||||||
|
* Redistributions of source code must retain the above
|
||||||
|
* copyright notice, this list of conditions and the
|
||||||
|
* following disclaimer.
|
||||||
|
*
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
*
|
||||||
|
* Neither the name of the copyright holder nor the names
|
||||||
|
* of any other contributors may be used to endorse or
|
||||||
|
* promote products derived from this software without
|
||||||
|
* specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||||
|
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
|
* OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libssh2_priv.h"
|
||||||
|
#include "userauth_kbd_packet.h"
|
||||||
|
|
||||||
|
int userauth_keyboard_interactive_decode_info_request(LIBSSH2_SESSION *session)
|
||||||
|
{
|
||||||
|
unsigned char *language_tag;
|
||||||
|
size_t language_tag_len;
|
||||||
|
unsigned int i;
|
||||||
|
unsigned char packet_type;
|
||||||
|
|
||||||
|
struct string_buf decoded;
|
||||||
|
|
||||||
|
decoded.data = session->userauth_kybd_data;
|
||||||
|
decoded.dataptr = session->userauth_kybd_data;
|
||||||
|
decoded.len = session->userauth_kybd_data_len;
|
||||||
|
|
||||||
|
if(session->userauth_kybd_data_len < 17) {
|
||||||
|
_libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL,
|
||||||
|
"userauth keyboard data buffer too small "
|
||||||
|
"to get length");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* byte SSH_MSG_USERAUTH_INFO_REQUEST */
|
||||||
|
_libssh2_get_byte(&decoded, &packet_type);
|
||||||
|
|
||||||
|
/* string name (ISO-10646 UTF-8) */
|
||||||
|
if(_libssh2_copy_string(session, &decoded,
|
||||||
|
&session->userauth_kybd_auth_name,
|
||||||
|
&session->userauth_kybd_auth_name_len) == -1) {
|
||||||
|
_libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||||
|
"Unable to decode "
|
||||||
|
"keyboard-interactive 'name' "
|
||||||
|
"request field");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* string instruction (ISO-10646 UTF-8) */
|
||||||
|
if(_libssh2_copy_string(session, &decoded,
|
||||||
|
&session->userauth_kybd_auth_instruction,
|
||||||
|
&session->userauth_kybd_auth_instruction_len)
|
||||||
|
== -1) {
|
||||||
|
_libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||||
|
"Unable to decode "
|
||||||
|
"keyboard-interactive 'instruction' "
|
||||||
|
"request field");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* string language tag (as defined in [RFC-3066]) */
|
||||||
|
if(_libssh2_get_string(&decoded, &language_tag,
|
||||||
|
&language_tag_len) == -1) {
|
||||||
|
_libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||||
|
"Unable to decode "
|
||||||
|
"keyboard-interactive 'language tag' "
|
||||||
|
"request field");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* int num-prompts */
|
||||||
|
if(_libssh2_get_u32(&decoded, &session->userauth_kybd_num_prompts) == -1) {
|
||||||
|
_libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL,
|
||||||
|
"Unable to decode "
|
||||||
|
"keyboard-interactive number of keyboard prompts");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(session->userauth_kybd_num_prompts > 100) {
|
||||||
|
_libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY,
|
||||||
|
"Too many replies for "
|
||||||
|
"keyboard-interactive prompts");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(session->userauth_kybd_num_prompts == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
session->userauth_kybd_prompts =
|
||||||
|
LIBSSH2_CALLOC(session,
|
||||||
|
sizeof(LIBSSH2_USERAUTH_KBDINT_PROMPT) *
|
||||||
|
session->userauth_kybd_num_prompts);
|
||||||
|
if(!session->userauth_kybd_prompts) {
|
||||||
|
_libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||||
|
"Unable to allocate memory for "
|
||||||
|
"keyboard-interactive prompts array");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
session->userauth_kybd_responses =
|
||||||
|
LIBSSH2_CALLOC(session,
|
||||||
|
sizeof(LIBSSH2_USERAUTH_KBDINT_RESPONSE) *
|
||||||
|
session->userauth_kybd_num_prompts);
|
||||||
|
if(!session->userauth_kybd_responses) {
|
||||||
|
_libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||||
|
"Unable to allocate memory for "
|
||||||
|
"keyboard-interactive responses array");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i = 0; i < session->userauth_kybd_num_prompts; i++) {
|
||||||
|
/* string prompt[1] (ISO-10646 UTF-8) */
|
||||||
|
if(_libssh2_copy_string(session, &decoded,
|
||||||
|
&session->userauth_kybd_prompts[i].text,
|
||||||
|
&session->userauth_kybd_prompts[i].length)
|
||||||
|
== -1) {
|
||||||
|
_libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||||
|
"Unable to decode "
|
||||||
|
"keyboard-interactive prompt message");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* boolean echo[1] */
|
||||||
|
if(_libssh2_get_boolean(&decoded,
|
||||||
|
&session->userauth_kybd_prompts[i].echo)
|
||||||
|
== -1) {
|
||||||
|
_libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL,
|
||||||
|
"Unable to decode "
|
||||||
|
"user auth keyboard prompt echo");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
43
src/userauth_kbd_packet.h
Normal file
43
src/userauth_kbd_packet.h
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
/* Copyright (c) 2022, Xaver Loppenstedt <xaver@loppenstedt.de>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms,
|
||||||
|
* with or without modification, are permitted provided
|
||||||
|
* that the following conditions are met:
|
||||||
|
*
|
||||||
|
* Redistributions of source code must retain the above
|
||||||
|
* copyright notice, this list of conditions and the
|
||||||
|
* following disclaimer.
|
||||||
|
*
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
*
|
||||||
|
* Neither the name of the copyright holder nor the names
|
||||||
|
* of any other contributors may be used to endorse or
|
||||||
|
* promote products derived from this software without
|
||||||
|
* specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||||
|
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
|
* OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LIBSSH2_USERAUTH_KBD_PARSE_H
|
||||||
|
#define __LIBSSH2_USERAUTH_KBD_PARSE_H
|
||||||
|
|
||||||
|
int userauth_keyboard_interactive_decode_info_request(LIBSSH2_SESSION *);
|
||||||
|
|
||||||
|
#endif /* __LIBSSH2_USERAUTH_KBD_PARSE_H */
|
@ -76,6 +76,8 @@ if(CRYPTO_BACKEND STREQUAL "OpenSSL" OR NOT CRYPTO_BACKEND)
|
|||||||
|
|
||||||
if(OPENSSL_FOUND)
|
if(OPENSSL_FOUND)
|
||||||
set(CRYPTO_BACKEND "OpenSSL")
|
set(CRYPTO_BACKEND "OpenSSL")
|
||||||
|
set(CRYPTO_BACKEND_DEFINE "LIBSSH2_OPENSSL")
|
||||||
|
set(CRYPTO_BACKEND_INCLUDE_DIR ${OPENSSL_INCLUDE_DIR})
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@ -85,6 +87,8 @@ if(CRYPTO_BACKEND STREQUAL "Libgcrypt" OR NOT CRYPTO_BACKEND)
|
|||||||
|
|
||||||
if(LIBGCRYPT_FOUND)
|
if(LIBGCRYPT_FOUND)
|
||||||
set(CRYPTO_BACKEND "Libgcrypt")
|
set(CRYPTO_BACKEND "Libgcrypt")
|
||||||
|
set(CRYPTO_BACKEND_DEFINE "LIBSSH2_LIBGCRYPT")
|
||||||
|
set(CRYPTO_BACKEND_INCLUDE_DIR ${LIBGCRYPT_INCLUDE_DIRS})
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@ -95,6 +99,8 @@ if(CRYPTO_BACKEND STREQUAL "WinCNG" OR NOT CRYPTO_BACKEND)
|
|||||||
|
|
||||||
if(HAVE_BCRYPT_H)
|
if(HAVE_BCRYPT_H)
|
||||||
set(CRYPTO_BACKEND "WinCNG")
|
set(CRYPTO_BACKEND "WinCNG")
|
||||||
|
set(CRYPTO_BACKEND_DEFINE "LIBSSH2_WINCNG")
|
||||||
|
set(CRYPTO_BACKEND_INCLUDE_DIR "")
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@ -104,6 +110,8 @@ if(CRYPTO_BACKEND STREQUAL "mbedTLS" OR NOT CRYPTO_BACKEND)
|
|||||||
|
|
||||||
if(MBEDTLS_FOUND)
|
if(MBEDTLS_FOUND)
|
||||||
set(CRYPTO_BACKEND "mbedTLS")
|
set(CRYPTO_BACKEND "mbedTLS")
|
||||||
|
set(CRYPTO_BACKEND_DEFINE "LIBSSH2_MBEDTLS")
|
||||||
|
set(CRYPTO_BACKEND_INCLUDE_DIR ${MBEDTLS_INCLUDE_DIR})
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@ -166,6 +174,34 @@ foreach(test ${TESTS})
|
|||||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}")
|
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
|
if(WIN32 AND BUILD_SHARED_LIBS)
|
||||||
|
# Workaround for Visual Studio
|
||||||
|
add_executable(test_keyboard_interactive_auth_info_request test_keyboard_interactive_auth_info_request.c ../src/userauth_kbd_packet.c ../src/misc.c)
|
||||||
|
else()
|
||||||
|
add_executable(test_keyboard_interactive_auth_info_request test_keyboard_interactive_auth_info_request.c ../src/userauth_kbd_packet.c)
|
||||||
|
endif()
|
||||||
|
target_compile_definitions(test_keyboard_interactive_auth_info_request PRIVATE "${CRYPTO_BACKEND_DEFINE}")
|
||||||
|
target_include_directories(test_keyboard_interactive_auth_info_request PRIVATE "${CMAKE_CURRENT_BINARY_DIR}" "../src/" "${CRYPTO_BACKEND_INCLUDE_DIR}")
|
||||||
|
find_program(GCOV_PATH gcov)
|
||||||
|
if(CMAKE_COMPILER_IS_GNUCC AND GCOV_PATH)
|
||||||
|
target_compile_options(test_keyboard_interactive_auth_info_request BEFORE PRIVATE
|
||||||
|
-g --coverage -fprofile-abs-path)
|
||||||
|
target_link_libraries(test_keyboard_interactive_auth_info_request ${LIBRARIES} libssh2 gcov)
|
||||||
|
else()
|
||||||
|
target_link_libraries(test_keyboard_interactive_auth_info_request ${LIBRARIES} libssh2)
|
||||||
|
endif()
|
||||||
|
add_test(
|
||||||
|
NAME test_keyboard_interactive_auth_info_request COMMAND $<TARGET_FILE:test_keyboard_interactive_auth_info_request>
|
||||||
|
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||||
|
|
||||||
|
add_custom_target(coverage
|
||||||
|
COMMAND gcovr -r "${CMAKE_SOURCE_DIR}" --exclude tests/*
|
||||||
|
COMMAND mkdir -p "${CMAKE_CURRENT_BINARY_DIR}/coverage/"
|
||||||
|
COMMAND gcovr -r "${CMAKE_SOURCE_DIR}" --exclude tests/* --html-details --output "${CMAKE_CURRENT_BINARY_DIR}/coverage/index.html")
|
||||||
|
|
||||||
|
add_custom_target(clean-coverage
|
||||||
|
COMMAND rm -rf "${CMAKE_CURRENT_BINARY_DIR}/coverage/")
|
||||||
|
|
||||||
add_target_to_copy_dependencies(
|
add_target_to_copy_dependencies(
|
||||||
TARGET copy_test_dependencies
|
TARGET copy_test_dependencies
|
||||||
DEPENDENCIES ${RUNTIME_DEPENDENCIES}
|
DEPENDENCIES ${RUNTIME_DEPENDENCIES}
|
||||||
|
335
tests/test_keyboard_interactive_auth_info_request.c
Normal file
335
tests/test_keyboard_interactive_auth_info_request.c
Normal file
@ -0,0 +1,335 @@
|
|||||||
|
/* Copyright (C) 2022 Xaver Loppenstedt
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms,
|
||||||
|
* with or without modification, are permitted provided
|
||||||
|
* that the following conditions are met:
|
||||||
|
*
|
||||||
|
* Redistributions of source code must retain the above
|
||||||
|
* copyright notice, this list of conditions and the
|
||||||
|
* following disclaimer.
|
||||||
|
*
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
*
|
||||||
|
* Neither the name of the copyright holder nor the names
|
||||||
|
* of any other contributors may be used to endorse or
|
||||||
|
* promote products derived from this software without
|
||||||
|
* specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||||
|
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
|
* OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "libssh2_priv.h"
|
||||||
|
#include "userauth_kbd_packet.h"
|
||||||
|
|
||||||
|
#define PASS 0
|
||||||
|
#define FAIL -1
|
||||||
|
|
||||||
|
struct expected {
|
||||||
|
int rc;
|
||||||
|
int last_error_code;
|
||||||
|
char *last_error_message;
|
||||||
|
};
|
||||||
|
struct test_case {
|
||||||
|
char *data;
|
||||||
|
int data_len;
|
||||||
|
struct expected expected;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define TEST_CASES_LEN 16
|
||||||
|
struct test_case test_cases[TEST_CASES_LEN] = {
|
||||||
|
/* to small */
|
||||||
|
{
|
||||||
|
NULL, 0,
|
||||||
|
{FAIL, -38,
|
||||||
|
"userauth keyboard data buffer too small to get length"}},
|
||||||
|
/* to small */
|
||||||
|
{
|
||||||
|
"1234", 4,
|
||||||
|
{FAIL, -38,
|
||||||
|
"userauth keyboard data buffer too small to get length"}},
|
||||||
|
/* smalest valid packet possible */
|
||||||
|
{
|
||||||
|
"<"
|
||||||
|
"\0\0\0\0"
|
||||||
|
"\0\0\0\0"
|
||||||
|
"\0\0\0\0"
|
||||||
|
"\0\0\0\0", 17,
|
||||||
|
{PASS, 0, ""}},
|
||||||
|
/* overrun name */
|
||||||
|
{
|
||||||
|
"<"
|
||||||
|
"\0\0\0\x7f"
|
||||||
|
"\0\0\0\0"
|
||||||
|
"\0\0\0\0"
|
||||||
|
"\0\0\0\0", 17,
|
||||||
|
{FAIL, -6,
|
||||||
|
"Unable to decode keyboard-interactive 'name' request field"}},
|
||||||
|
/* overrun instruction */
|
||||||
|
{
|
||||||
|
"<"
|
||||||
|
"\0\0\0\0"
|
||||||
|
"\0\0\0\x7f"
|
||||||
|
"\0\0\0\0"
|
||||||
|
"\0\0\0\0", 17,
|
||||||
|
{FAIL, -6,
|
||||||
|
"Unable to decode keyboard-interactive 'instruction' "
|
||||||
|
"request field"}},
|
||||||
|
/* overrun language */
|
||||||
|
{
|
||||||
|
"<"
|
||||||
|
"\0\0\0\0"
|
||||||
|
"\0\0\0\0"
|
||||||
|
"\0\0\0\x7f"
|
||||||
|
"\0\0\0\0", 17,
|
||||||
|
{FAIL, -6, "Unable to decode keyboard-interactive 'language tag' "
|
||||||
|
"request field"}},
|
||||||
|
/* underrun prompt number */
|
||||||
|
{
|
||||||
|
"<"
|
||||||
|
"\0\0\0\x01"
|
||||||
|
"\0\0\0\0"
|
||||||
|
"\0\0\0\0"
|
||||||
|
"\0\0\0\0", 17,
|
||||||
|
{FAIL, -38,
|
||||||
|
"Unable to decode keyboard-interactive number of "
|
||||||
|
"keyboard prompts"}},
|
||||||
|
/* too many prompts */
|
||||||
|
{
|
||||||
|
"<"
|
||||||
|
"\0\0\0\0"
|
||||||
|
"\0\0\0\0"
|
||||||
|
"\0\0\0\0"
|
||||||
|
"\0\0\0\x7f", 17,
|
||||||
|
{FAIL, -41, "Too many replies for keyboard-interactive prompts"}},
|
||||||
|
/* empty prompt */
|
||||||
|
{
|
||||||
|
"<"
|
||||||
|
"\0\0\0\0"
|
||||||
|
"\0\0\0\0"
|
||||||
|
"\0\0\0\0"
|
||||||
|
"\0\0\0\x01"
|
||||||
|
"\0\0\0\0"
|
||||||
|
"\0", 22, {PASS, 0, ""}},
|
||||||
|
/* copied from OpenSSH */
|
||||||
|
{
|
||||||
|
"<"
|
||||||
|
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01"
|
||||||
|
"\0\0\0\x0aPassword: \0", 32, {PASS, 0, ""}},
|
||||||
|
/* overrun in prompt text */
|
||||||
|
{
|
||||||
|
"<"
|
||||||
|
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01"
|
||||||
|
"\0\0\0\x7bPassword: \0", 32,
|
||||||
|
{FAIL, -6, "Unable to decode keyboard-interactive "
|
||||||
|
"prompt message"}},
|
||||||
|
/* no echo prompt boolean */
|
||||||
|
{
|
||||||
|
"<"
|
||||||
|
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01"
|
||||||
|
"\0\0\0\x0bPassword: \0", 32,
|
||||||
|
{FAIL, -38, "Unable to decode user auth keyboard prompt echo"}},
|
||||||
|
/* two prompts */
|
||||||
|
{
|
||||||
|
"<"
|
||||||
|
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x02"
|
||||||
|
"\0\0\0\x0aPassword: \0"
|
||||||
|
"\0\0\0\x07Token: \1", 44,
|
||||||
|
{PASS, 0, ""}},
|
||||||
|
/* example from RFC 4256 */
|
||||||
|
{
|
||||||
|
"<"
|
||||||
|
"\0\0\0\x19""CRYPTOCard Authentication"
|
||||||
|
"\0\0\0\x1b""The challenge is '14315716'"
|
||||||
|
"\0\0\0\x05""en-US"
|
||||||
|
"\0\0\0\x01"
|
||||||
|
"\0\0\0\x0aResponse: "
|
||||||
|
"\x01"
|
||||||
|
, 89, {PASS, 0, ""}},
|
||||||
|
/* three prompts, 3rd missing*/
|
||||||
|
{
|
||||||
|
"<"
|
||||||
|
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x03"
|
||||||
|
"\0\0\0\x0aPassword: \0"
|
||||||
|
"\0\0\0\x07Token: \1", 44,
|
||||||
|
{FAIL, -6,
|
||||||
|
"Unable to decode keyboard-interactive prompt message"}},
|
||||||
|
/* overflow language on 32 bit platform */
|
||||||
|
{
|
||||||
|
"<"
|
||||||
|
"\0\0\0\x19"
|
||||||
|
"\0\0\0\x01"
|
||||||
|
"\0\0\0\x05""PWN3D\0\1\2\3\4\5\6\7\1\2\3"
|
||||||
|
"\x01"
|
||||||
|
"\0\0\0\x1b""The challenge is '14315716'"
|
||||||
|
"\xff\xff\xff\xc4""en-US"
|
||||||
|
"\0\0\0\x01"
|
||||||
|
"\0\0\0\x0aResponse: "
|
||||||
|
"\x01",
|
||||||
|
89,
|
||||||
|
{FAIL, -6,
|
||||||
|
"Unable to decode keyboard-interactive 'language tag' "
|
||||||
|
"request field"}},
|
||||||
|
};
|
||||||
|
|
||||||
|
#define FAILED_MALLOC_TEST_CASES_LEN 2
|
||||||
|
struct test_case failed_malloc_test_cases[FAILED_MALLOC_TEST_CASES_LEN] = {
|
||||||
|
/* malloc fail */
|
||||||
|
{
|
||||||
|
"<"
|
||||||
|
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01"
|
||||||
|
"\0\0\0\x0aPassword: \0", 32,
|
||||||
|
{FAIL, -6,
|
||||||
|
"Unable to allocate memory for "
|
||||||
|
"keyboard-interactive prompts array"}},
|
||||||
|
/* malloc fail */
|
||||||
|
{
|
||||||
|
"<"
|
||||||
|
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01"
|
||||||
|
"\0\0\0\x0aPassword: \0", 32,
|
||||||
|
{FAIL, -6,
|
||||||
|
"Unable to allocate memory for "
|
||||||
|
"keyboard-interactive responses array"
|
||||||
|
}}
|
||||||
|
};
|
||||||
|
|
||||||
|
static int alloc_count = 0;
|
||||||
|
static int free_count = 0;
|
||||||
|
|
||||||
|
/* libssh2_default_alloc
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
LIBSSH2_ALLOC_FUNC(test_alloc)
|
||||||
|
{
|
||||||
|
alloc_count++;
|
||||||
|
|
||||||
|
int *threshold_int_ptr = *abstract;
|
||||||
|
if (*abstract != NULL && *threshold_int_ptr == alloc_count) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return malloc(count);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* libssh2_default_free
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
LIBSSH2_FREE_FUNC(test_free)
|
||||||
|
{
|
||||||
|
(void) abstract;
|
||||||
|
free_count++;
|
||||||
|
free(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int test_case(int num,
|
||||||
|
char *data, int data_len, void *abstract,
|
||||||
|
struct expected expected)
|
||||||
|
{
|
||||||
|
alloc_count = 0;
|
||||||
|
free_count = 0;
|
||||||
|
LIBSSH2_SESSION *session = NULL;
|
||||||
|
session = libssh2_session_init_ex(test_alloc, test_free, NULL, abstract);
|
||||||
|
if(session == NULL) {
|
||||||
|
fprintf(stderr, "libssh2_session_init_ex failed\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
session->userauth_kybd_data = LIBSSH2_ALLOC(session, data_len);
|
||||||
|
session->userauth_kybd_data_len = data_len;
|
||||||
|
memcpy(session->userauth_kybd_data, data, data_len);
|
||||||
|
|
||||||
|
int rc = userauth_keyboard_interactive_decode_info_request(session);
|
||||||
|
|
||||||
|
if(rc != expected.rc) {
|
||||||
|
fprintf(stdout,
|
||||||
|
"Test case %d: expected return code to be %d got %d\n",
|
||||||
|
num, expected.rc, rc);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *message;
|
||||||
|
int error_code = libssh2_session_last_error(session, &message, NULL, 0);
|
||||||
|
|
||||||
|
if(expected.last_error_code != error_code) {
|
||||||
|
fprintf(stdout,
|
||||||
|
"Test case %d: expected last error code to be "
|
||||||
|
"\"%d\" got \"%d\"\n",
|
||||||
|
num, expected.last_error_code, error_code);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strcmp(expected.last_error_message, message) != 0) {
|
||||||
|
fprintf(stdout,
|
||||||
|
"Test case %d: expected last error message to be "
|
||||||
|
"\"%s\" got \"%s\"\n",
|
||||||
|
num, expected.last_error_message, message);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
libssh2_session_free(session);
|
||||||
|
|
||||||
|
fprintf(stderr, "Test case %d passed\n", num);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i = 0; i < TEST_CASES_LEN; i++) {
|
||||||
|
test_case(i + 1,
|
||||||
|
test_cases[i].data, test_cases[i].data_len,
|
||||||
|
NULL,
|
||||||
|
test_cases[i].expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i = 0; i < FAILED_MALLOC_TEST_CASES_LEN; i++) {
|
||||||
|
int tc = i + TEST_CASES_LEN + 1;
|
||||||
|
int malloc_call_num = 5 + i;
|
||||||
|
test_case(tc,
|
||||||
|
failed_malloc_test_cases[i].data,
|
||||||
|
failed_malloc_test_cases[i].data_len,
|
||||||
|
&malloc_call_num,
|
||||||
|
failed_malloc_test_cases[i].expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Workaround for Visual Studio */
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
int
|
||||||
|
bcrypt_pbkdf(const char *pass, size_t passlen, const uint8_t *salt,
|
||||||
|
size_t saltlen,
|
||||||
|
uint8_t *key, size_t keylen, unsigned int rounds)
|
||||||
|
{
|
||||||
|
(void)pass;
|
||||||
|
(void)passlen;
|
||||||
|
(void)salt;
|
||||||
|
(void)saltlen;
|
||||||
|
(void)key;
|
||||||
|
(void)keylen;
|
||||||
|
(void)rounds;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
Reference in New Issue
Block a user