Skip to content

Commit 83853f8

Browse files
authored
Use modern API in userauth_keyboard_interactive() (libssh2#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
1 parent ead7000 commit 83853f8

11 files changed

+616
-212
lines changed

Makefile.inc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
CSOURCES = channel.c comp.c crypt.c hostkey.c kex.c mac.c misc.c \
22
packet.c publickey.c scp.c session.c sftp.c userauth.c transport.c \
3+
userauth_kbd_packet.c \
34
version.c knownhost.c agent.c $(CRYPTO_CSOURCES) pem.c keepalive.c global.c \
45
blowfish.c bcrypt_pbkdf.c agent_win.c
56

include/libssh2.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -272,8 +272,8 @@ typedef off_t libssh2_struct_stat_size;
272272

273273
typedef struct _LIBSSH2_USERAUTH_KBDINT_PROMPT
274274
{
275-
char *text;
276-
unsigned int length;
275+
unsigned char *text;
276+
size_t length;
277277
unsigned char echo;
278278
} LIBSSH2_USERAUTH_KBDINT_PROMPT;
279279

src/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,8 @@ set(SOURCES
207207
sftp.h
208208
transport.c
209209
transport.h
210+
userauth_kbd_packet.c
211+
userauth_kbd_packet.h
210212
userauth.c
211213
userauth.h
212214
version.c)

src/libssh2_priv.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -760,10 +760,10 @@ struct _LIBSSH2_SESSION
760760
size_t userauth_kybd_data_len;
761761
unsigned char *userauth_kybd_packet;
762762
size_t userauth_kybd_packet_len;
763-
unsigned int userauth_kybd_auth_name_len;
764-
char *userauth_kybd_auth_name;
765-
unsigned userauth_kybd_auth_instruction_len;
766-
char *userauth_kybd_auth_instruction;
763+
size_t userauth_kybd_auth_name_len;
764+
unsigned char *userauth_kybd_auth_name;
765+
size_t userauth_kybd_auth_instruction_len;
766+
unsigned char *userauth_kybd_auth_instruction;
767767
unsigned int userauth_kybd_num_prompts;
768768
int userauth_kybd_auth_failure;
769769
LIBSSH2_USERAUTH_KBDINT_PROMPT *userauth_kybd_prompts;

src/misc.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -732,6 +732,29 @@ void _libssh2_string_buf_free(LIBSSH2_SESSION *session, struct string_buf *buf)
732732
buf = NULL;
733733
}
734734

735+
int _libssh2_get_byte(struct string_buf *buf, unsigned char *out)
736+
{
737+
if(!_libssh2_check_length(buf, 1)) {
738+
return -1;
739+
}
740+
741+
*out = buf->dataptr[0];
742+
buf->dataptr += 1;
743+
return 0;
744+
}
745+
746+
int _libssh2_get_boolean(struct string_buf *buf, unsigned char *out)
747+
{
748+
if(!_libssh2_check_length(buf, 1)) {
749+
return -1;
750+
}
751+
752+
753+
*out = buf->dataptr[0] == 0 ? 0 : 1;
754+
buf->dataptr += 1;
755+
return 0;
756+
}
757+
735758
int _libssh2_get_u32(struct string_buf *buf, uint32_t *out)
736759
{
737760
if(!_libssh2_check_length(buf, 4)) {

src/misc.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ void _libssh2_explicit_zero(void *buf, size_t size);
9191
struct string_buf* _libssh2_string_buf_new(LIBSSH2_SESSION *session);
9292
void _libssh2_string_buf_free(LIBSSH2_SESSION *session,
9393
struct string_buf *buf);
94+
int _libssh2_get_boolean(struct string_buf *buf, unsigned char *out);
95+
int _libssh2_get_byte(struct string_buf *buf, unsigned char *out);
9496
int _libssh2_get_u32(struct string_buf *buf, uint32_t *out);
9597
int _libssh2_get_u64(struct string_buf *buf, libssh2_uint64_t *out);
9698
int _libssh2_match_string(struct string_buf *buf, const char *match);

src/userauth.c

Lines changed: 6 additions & 206 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
#include "transport.h"
5353
#include "session.h"
5454
#include "userauth.h"
55+
#include "userauth_kbd_packet.h"
5556

5657
/* libssh2_userauth_list
5758
*
@@ -1878,13 +1879,13 @@ userauth_keyboard_interactive(LIBSSH2_SESSION * session,
18781879
((*response_callback)))
18791880
{
18801881
unsigned char *s;
1882+
18811883
int rc;
18821884

18831885
static const unsigned char reply_codes[4] = {
18841886
SSH_MSG_USERAUTH_SUCCESS,
18851887
SSH_MSG_USERAUTH_FAILURE, SSH_MSG_USERAUTH_INFO_REQUEST, 0
18861888
};
1887-
unsigned int language_tag_len;
18881889
unsigned int i;
18891890

18901891
if(session->userauth_kybd_state == libssh2_NB_state_idle) {
@@ -2007,215 +2008,14 @@ userauth_keyboard_interactive(LIBSSH2_SESSION * session,
20072008
}
20082009

20092010
/* server requested PAM-like conversation */
2010-
s = session->userauth_kybd_data + 1;
2011-
2012-
if(session->userauth_kybd_data_len >= 5) {
2013-
/* string name (ISO-10646 UTF-8) */
2014-
session->userauth_kybd_auth_name_len = _libssh2_ntohu32(s);
2015-
if(session->userauth_kybd_auth_name_len >
2016-
session->userauth_kybd_data_len - 5)
2017-
return _libssh2_error(session,
2018-
LIBSSH2_ERROR_OUT_OF_BOUNDARY,
2019-
"Bad keyboard auth name");
2020-
s += 4;
2021-
}
2022-
else {
2023-
_libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL,
2024-
"userauth keyboard data buffer too small"
2025-
"to get length");
2026-
goto cleanup;
2027-
}
2028-
2029-
if(session->userauth_kybd_auth_name_len) {
2030-
session->userauth_kybd_auth_name =
2031-
LIBSSH2_ALLOC(session,
2032-
session->userauth_kybd_auth_name_len);
2033-
if(!session->userauth_kybd_auth_name) {
2034-
_libssh2_error(session, LIBSSH2_ERROR_ALLOC,
2035-
"Unable to allocate memory for "
2036-
"keyboard-interactive 'name' "
2037-
"request field");
2038-
goto cleanup;
2039-
}
2040-
if(s + session->userauth_kybd_auth_name_len <=
2041-
session->userauth_kybd_data +
2042-
session->userauth_kybd_data_len) {
2043-
memcpy(session->userauth_kybd_auth_name, s,
2044-
session->userauth_kybd_auth_name_len);
2045-
s += session->userauth_kybd_auth_name_len;
2046-
}
2047-
else {
2048-
_libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL,
2049-
"userauth keyboard data buffer too small"
2050-
"for auth name");
2051-
goto cleanup;
2052-
}
2053-
}
2054-
2055-
if(s + 4 <= session->userauth_kybd_data +
2056-
session->userauth_kybd_data_len) {
2057-
/* string instruction (ISO-10646 UTF-8) */
2058-
session->userauth_kybd_auth_instruction_len =
2059-
_libssh2_ntohu32(s);
2060-
s += 4;
2061-
}
2062-
else {
2063-
_libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL,
2064-
"userauth keyboard data buffer too small"
2065-
"for auth instruction length");
2011+
if(userauth_keyboard_interactive_decode_info_request(session)
2012+
< 0) {
20662013
goto cleanup;
20672014
}
20682015

2069-
if(session->userauth_kybd_auth_instruction_len) {
2070-
session->userauth_kybd_auth_instruction =
2071-
LIBSSH2_ALLOC(session,
2072-
session->userauth_kybd_auth_instruction_len);
2073-
if(!session->userauth_kybd_auth_instruction) {
2074-
_libssh2_error(session, LIBSSH2_ERROR_ALLOC,
2075-
"Unable to allocate memory for "
2076-
"keyboard-interactive 'instruction' "
2077-
"request field");
2078-
goto cleanup;
2079-
}
2080-
if(s + session->userauth_kybd_auth_instruction_len <=
2081-
session->userauth_kybd_data +
2082-
session->userauth_kybd_data_len) {
2083-
memcpy(session->userauth_kybd_auth_instruction, s,
2084-
session->userauth_kybd_auth_instruction_len);
2085-
s += session->userauth_kybd_auth_instruction_len;
2086-
}
2087-
else {
2088-
_libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL,
2089-
"userauth keyboard data buffer too small"
2090-
"for auth instruction");
2091-
goto cleanup;
2092-
}
2093-
}
2094-
2095-
if(s + 4 <= session->userauth_kybd_data +
2096-
session->userauth_kybd_data_len) {
2097-
/* string language tag (as defined in [RFC-3066]) */
2098-
language_tag_len = _libssh2_ntohu32(s);
2099-
s += 4;
2100-
}
2101-
else {
2102-
_libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL,
2103-
"userauth keyboard data buffer too small"
2104-
"for auth language tag length");
2105-
goto cleanup;
2106-
}
2107-
2108-
if(s + language_tag_len <= session->userauth_kybd_data +
2109-
session->userauth_kybd_data_len) {
2110-
/* ignoring this field as deprecated */
2111-
s += language_tag_len;
2112-
}
2113-
else {
2114-
_libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL,
2115-
"userauth keyboard data buffer too small"
2116-
"for auth language tag");
2117-
goto cleanup;
2118-
}
2119-
2120-
if(s + 4 <= session->userauth_kybd_data +
2121-
session->userauth_kybd_data_len) {
2122-
/* int num-prompts */
2123-
session->userauth_kybd_num_prompts = _libssh2_ntohu32(s);
2124-
s += 4;
2125-
}
2126-
else {
2127-
_libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL,
2128-
"userauth keyboard data buffer too small"
2129-
"for auth num keyboard prompts");
2130-
goto cleanup;
2131-
}
2132-
2133-
if(session->userauth_kybd_num_prompts > 100) {
2134-
_libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY,
2135-
"Too many replies for "
2136-
"keyboard-interactive prompts");
2137-
goto cleanup;
2138-
}
2139-
2140-
if(session->userauth_kybd_num_prompts) {
2141-
session->userauth_kybd_prompts =
2142-
LIBSSH2_CALLOC(session,
2143-
sizeof(LIBSSH2_USERAUTH_KBDINT_PROMPT) *
2144-
session->userauth_kybd_num_prompts);
2145-
if(!session->userauth_kybd_prompts) {
2146-
_libssh2_error(session, LIBSSH2_ERROR_ALLOC,
2147-
"Unable to allocate memory for "
2148-
"keyboard-interactive prompts array");
2149-
goto cleanup;
2150-
}
2151-
2152-
session->userauth_kybd_responses =
2153-
LIBSSH2_CALLOC(session,
2154-
sizeof(LIBSSH2_USERAUTH_KBDINT_RESPONSE) *
2155-
session->userauth_kybd_num_prompts);
2156-
if(!session->userauth_kybd_responses) {
2157-
_libssh2_error(session, LIBSSH2_ERROR_ALLOC,
2158-
"Unable to allocate memory for "
2159-
"keyboard-interactive responses array");
2160-
goto cleanup;
2161-
}
2162-
2163-
for(i = 0; i < session->userauth_kybd_num_prompts; i++) {
2164-
if(s + 4 <= session->userauth_kybd_data +
2165-
session->userauth_kybd_data_len) {
2166-
/* string prompt[1] (ISO-10646 UTF-8) */
2167-
session->userauth_kybd_prompts[i].length =
2168-
_libssh2_ntohu32(s);
2169-
s += 4;
2170-
}
2171-
else {
2172-
_libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL,
2173-
"userauth keyboard data buffer too "
2174-
"small for auth keyboard "
2175-
"prompt length");
2176-
goto cleanup;
2177-
}
2178-
2179-
session->userauth_kybd_prompts[i].text =
2180-
LIBSSH2_CALLOC(session,
2181-
session->userauth_kybd_prompts[i].
2182-
length);
2183-
if(!session->userauth_kybd_prompts[i].text) {
2184-
_libssh2_error(session, LIBSSH2_ERROR_ALLOC,
2185-
"Unable to allocate memory for "
2186-
"keyboard-interactive prompt message");
2187-
goto cleanup;
2188-
}
2189-
2190-
if(s + session->userauth_kybd_prompts[i].length <=
2191-
session->userauth_kybd_data +
2192-
session->userauth_kybd_data_len) {
2193-
memcpy(session->userauth_kybd_prompts[i].text, s,
2194-
session->userauth_kybd_prompts[i].length);
2195-
s += session->userauth_kybd_prompts[i].length;
2196-
}
2197-
else {
2198-
_libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL,
2199-
"userauth keyboard data buffer too "
2200-
"small for auth keyboard prompt");
2201-
goto cleanup;
2202-
}
2203-
if(s < session->userauth_kybd_data +
2204-
session->userauth_kybd_data_len) {
2205-
/* boolean echo[1] */
2206-
session->userauth_kybd_prompts[i].echo = *s++;
2207-
}
2208-
else {
2209-
_libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL,
2210-
"userauth keyboard data buffer too "
2211-
"small for auth keyboard prompt echo");
2212-
goto cleanup;
2213-
}
2214-
}
2215-
}
2216-
2217-
response_callback(session->userauth_kybd_auth_name,
2016+
response_callback((const char *)session->userauth_kybd_auth_name,
22182017
session->userauth_kybd_auth_name_len,
2018+
(const char *)
22192019
session->userauth_kybd_auth_instruction,
22202020
session->userauth_kybd_auth_instruction_len,
22212021
session->userauth_kybd_num_prompts,

0 commit comments

Comments
 (0)