1
1

Add keyboard interactive authentication.

Implementation contributed by Mikhail Gusarov.
Этот коммит содержится в:
Sara Golemon 2005-06-11 19:18:06 +00:00
родитель 9203a62789
Коммит da653774aa
4 изменённых файлов: 223 добавлений и 0 удалений

2
README
Просмотреть файл

@ -4,6 +4,8 @@ libssh2 - SSH2 library
Version 0.11 Version 0.11
------------ ------------
Added libssh2_userauth_keyboard_interactive_ex() -- Code contributed by Mikhail Gusarov
Added libssh2_channel_receive_window_adjust() to be able to increase the size of the receive window. Added libssh2_channel_receive_window_adjust() to be able to increase the size of the receive window.
Added queueing for small window_adjust packets to avoid unnecessary packet conversation. Added queueing for small window_adjust packets to avoid unnecessary packet conversation.

Просмотреть файл

@ -107,6 +107,22 @@ typedef long long libssh2_int64_t;
#define LIBSSH2_REALLOC_FUNC(name) void *name(void *ptr, size_t count, void **abstract) #define LIBSSH2_REALLOC_FUNC(name) void *name(void *ptr, size_t count, void **abstract)
#define LIBSSH2_FREE_FUNC(name) void name(void *ptr, void **abstract) #define LIBSSH2_FREE_FUNC(name) void name(void *ptr, void **abstract)
typedef struct _LIBSSH2_USERAUTH_KBDINT_PROMPT
{
char* text;
unsigned int length;
unsigned char echo;
} LIBSSH2_USERAUTH_KBDINT_PROMPT;
typedef struct _LIBSSH2_USERAUTH_KBDINT_RESPONSE
{
char* text;
unsigned int length;
} LIBSSH2_USERAUTH_KBDINT_RESPONSE;
/* 'keyboard-interactive' authentication callback */
#define LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC(name_) void name_(const char* name, int name_len, const char* instruction, int instruction_len, int num_prompts, const LIBSSH2_USERAUTH_KBDINT_PROMPT* prompts, LIBSSH2_USERAUTH_KBDINT_RESPONSE* responses)
/* Callbacks for special SSH packets */ /* Callbacks for special SSH packets */
#define LIBSSH2_IGNORE_FUNC(name) void name(LIBSSH2_SESSION *session, const char *message, int message_len, void **abstract) #define LIBSSH2_IGNORE_FUNC(name) void name(LIBSSH2_SESSION *session, const char *message, int message_len, void **abstract)
#define LIBSSH2_DEBUG_FUNC(name) void name(LIBSSH2_SESSION *session, int always_display, const char *message, int message_len, const char *language, int language_len,void **abstract) #define LIBSSH2_DEBUG_FUNC(name) void name(LIBSSH2_SESSION *session, int always_display, const char *message, int message_len, const char *language, int language_len,void **abstract)
@ -274,6 +290,17 @@ LIBSSH2_API int libssh2_userauth_hostbased_fromfile_ex(LIBSSH2_SESSION *session,
#define libssh2_userauth_hostbased_fromfile(session, username, publickey, privatekey, passphrase, hostname) \ #define libssh2_userauth_hostbased_fromfile(session, username, publickey, privatekey, passphrase, hostname) \
libssh2_userauth_hostbased_fromfile_ex((session), (username), strlen(username), (publickey), (privatekey), (passphrase), (hostname), strlen(hostname), (username), strlen(username)) libssh2_userauth_hostbased_fromfile_ex((session), (username), strlen(username), (publickey), (privatekey), (passphrase), (hostname), strlen(hostname), (username), strlen(username))
/*
* response_callback is provided with filled by library prompts array,
* but client must allocate and fill individual responses. Responses
* array is already allocated. Responses data will be freed by libssh2
* after callback return, but before subsequent callback invokation.
*/
LIBSSH2_API int libssh2_userauth_keyboard_interactive_ex(LIBSSH2_SESSION* session, const char* username, int username_len,
LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC((*response_callback)));
#define libssh2_userauth_keyboard_interactive(session, username, response_callback) \
libssh2_userauth_keyboard_interactive_ex((session), (username), strlen(username), (response_callback))
LIBSSH2_API int libssh2_poll(LIBSSH2_POLLFD *fds, unsigned int nfds, long timeout); LIBSSH2_API int libssh2_poll(LIBSSH2_POLLFD *fds, unsigned int nfds, long timeout);
/* Channel API */ /* Channel API */

Просмотреть файл

@ -407,6 +407,9 @@ void _libssh2_debug(LIBSSH2_SESSION *session, int context, const char *format, .
#define SSH_MSG_USERAUTH_PK_OK 60 #define SSH_MSG_USERAUTH_PK_OK 60
/* "password" method */ /* "password" method */
#define SSH_MSG_USERAUTH_PASSWD_CHANGEREQ 60 #define SSH_MSG_USERAUTH_PASSWD_CHANGEREQ 60
/* "keyboard-interactive" method */
#define SSH_MSG_USERAUTH_INFO_REQUEST 60
#define SSH_MSG_USERAUTH_INFO_RESPONSE 61
/* Channels */ /* Channels */
#define SSH_MSG_GLOBAL_REQUEST 80 #define SSH_MSG_GLOBAL_REQUEST 80

Просмотреть файл

@ -652,3 +652,194 @@ LIBSSH2_API int libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session,
return -1; return -1;
} }
/* }}} */ /* }}} */
/* {{{ libssh2_userauth_keyboard_interactive
* Authenticate using a challenge-response authentication
*/
LIBSSH2_API int libssh2_userauth_keyboard_interactive_ex(LIBSSH2_SESSION *session, const char *username, int username_len,
LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC((*response_callback)))
{
unsigned char *s, *data; /* packet */
unsigned long packet_len;
packet_len = 1 /* byte SSH_MSG_USERAUTH_REQUEST */
+ 4 + username_len /* string user name (ISO-10646 UTF-8, as defined in [RFC-3629]) */
+ 4 + 14 /* string service name (US-ASCII) */
+ 4 + 20 /* string "keyboard-interactive" (US-ASCII) */
+ 4 + 0 /* string language tag (as defined in [RFC-3066]) */
+ 4 + 0 /* string submethods (ISO-10646 UTF-8) */
;
if (!(data = s = LIBSSH2_ALLOC(session, packet_len))) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for keyboard-interactive authentication", 0);
return -1;
}
*s++ = SSH_MSG_USERAUTH_REQUEST;
/* user name */
libssh2_htonu32(s, username_len); s += 4;
memcpy(s, username, username_len); s += username_len;
/* service name */
libssh2_htonu32(s, sizeof("ssh-connection")); s += 4;
memcpy(s, "ssh-connection", sizeof("ssh-connection")); s += sizeof("ssh-connection");
/* "keyboard-interactive" */
libssh2_htonu32(s, sizeof("keyboard-interactive")); s += 4;
memcpy(s, "keyboard-interactive", sizeof("keyboard-interactive")); s += sizeof("keyboard-interactive");
/* language tag */
libssh2_htonu32(s, 0); s += 4;
/* submethods */
libssh2_htonu32(s, 0); s += 4;
if (libssh2_packet_write(session, data, packet_len)) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send keyboard-interactive request", 0);
LIBSSH2_FREE(session, data);
return -1;
}
LIBSSH2_FREE(session, data);
for (;;) {
unsigned char reply_codes[4] = { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, SSH_MSG_USERAUTH_INFO_REQUEST, 0 };
unsigned int auth_name_len;
char* auth_name = NULL;
unsigned auth_instruction_len;
char* auth_instruction = NULL;
unsigned int language_tag_len;
unsigned long data_len;
unsigned int num_prompts = 0;
unsigned int i;
int auth_failure = 1;
LIBSSH2_USERAUTH_KBDINT_PROMPT* prompts = NULL;
LIBSSH2_USERAUTH_KBDINT_RESPONSE* responses = NULL;
if (libssh2_packet_requirev(session, reply_codes, &data, &data_len)) {
return -1;
}
if (data[0] == SSH_MSG_USERAUTH_SUCCESS) {
LIBSSH2_FREE(session, data);
session->state |= LIBSSH2_STATE_AUTHENTICATED;
return 0;
}
if (data[0] == SSH_MSG_USERAUTH_FAILURE) {
LIBSSH2_FREE(session, data);
return -1;
}
/* server requested PAM-like conversation */
s = data + 1;
/* string name (ISO-10646 UTF-8) */
auth_name_len = libssh2_ntohu32(s); s += 4;
if (!(auth_name = LIBSSH2_ALLOC(session, auth_name_len))) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for keyboard-interactive 'name' request field", 0);
goto cleanup;
}
memcpy(auth_name, s, auth_name_len); s += auth_name_len;
/* string instruction (ISO-10646 UTF-8) */
auth_instruction_len = libssh2_ntohu32(s); s += 4;
if (!(auth_instruction = LIBSSH2_ALLOC(session, auth_instruction_len))) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for keyboard-interactive 'instruction' request field", 0);
goto cleanup;
}
memcpy(auth_instruction, s, auth_instruction_len); s += auth_instruction_len;
/* string language tag (as defined in [RFC-3066]) */
language_tag_len = libssh2_ntohu32(s); s += 4;
/* ignoring this field as deprecated */ s += language_tag_len;
/* int num-prompts */
num_prompts = libssh2_ntohu32(s); s += 4;
prompts = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_USERAUTH_KBDINT_PROMPT) * num_prompts);
if (!prompts) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for keyboard-interactive prompts array", 0);
goto cleanup;
}
memset(prompts, 0, sizeof(LIBSSH2_USERAUTH_KBDINT_PROMPT) * num_prompts);
responses = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_USERAUTH_KBDINT_RESPONSE) * num_prompts);
if (!responses) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for keyboard-interactive responses array", 0);
goto cleanup;
}
memset(responses, 0, sizeof(LIBSSH2_USERAUTH_KBDINT_RESPONSE) * num_prompts);
for(i = 0; i != num_prompts; ++i) {
/* string prompt[1] (ISO-10646 UTF-8) */
prompts[i].length = libssh2_ntohu32(s); s += 4;
if (!(prompts[i].text = LIBSSH2_ALLOC(session, prompts[i].length))) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for keyboard-interactive prompt message", 0);
goto cleanup;
}
memcpy(prompts[i].text, s, prompts[i].length); s += prompts[i].length;
/* boolean echo[1] */
prompts[i].echo = *s++;
}
response_callback(auth_name, auth_name_len, auth_instruction, auth_instruction_len, num_prompts, prompts, responses);
packet_len = 1 /* byte SSH_MSG_USERAUTH_INFO_RESPONSE */
+ 4 /* int num-responses */
;
for (i = 0; i != num_prompts; ++i) {
packet_len += 4 + responses[i].length; /* string response[1] (ISO-10646 UTF-8) */
}
if (!(data = s = LIBSSH2_ALLOC(session, packet_len))) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for keyboard-interactive response packet", 0);
goto cleanup;
}
*s = SSH_MSG_USERAUTH_INFO_RESPONSE; s++;
libssh2_htonu32(s, num_prompts); s += 4;
for (i = 0; i != num_prompts; ++i) {
libssh2_htonu32(s, responses[i].length); s += 4;
memcpy(s, responses[i].text, responses[i].length); s += responses[i].length;
}
if (libssh2_packet_write(session, data, packet_len)) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send userauth-keyboard-interactive request", 0);
goto cleanup;
}
auth_failure = 0;
cleanup:
/* It's safe to clean all the data here, because unallocated pointers
* are filled by zeroes
*/
LIBSSH2_FREE(session, data);
if (prompts) {
for (i = 0; i != num_prompts; ++i) {
LIBSSH2_FREE(session, prompts[i].text);
}
}
if (responses) {
for (i = 0; i != num_prompts; ++i) {
LIBSSH2_FREE(session, responses[i].text);
}
}
LIBSSH2_FREE(session, prompts);
LIBSSH2_FREE(session, responses);
if (auth_failure) {
return -1;
}
}
}
/* }}} */