1
1

Made parts of SSH asynchronous (inc kex1)

Этот коммит содержится в:
Aris Adamantiadis 2010-01-24 21:03:03 +01:00
родитель 6ae558b541
Коммит 758df26582
9 изменённых файлов: 201 добавлений и 210 удалений

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

@ -78,5 +78,9 @@ uint32_t ssh_channel_new_id(ssh_session session);
ssh_channel ssh_channel_from_local(ssh_session session, uint32_t id);
int channel_write_common(ssh_channel channel, const void *data,
uint32_t len, int is_stderr);
#ifdef WITH_SSH1
SSH_PACKET_CALLBACK(ssh_packet_data1);
SSH_PACKET_CALLBACK(ssh_packet_close1);
#endif
#endif /* CHANNELS_H_ */

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

@ -26,5 +26,8 @@
#include "libssh/callbacks.h"
SSH_PACKET_CALLBACK(ssh_packet_kexinit);
#ifdef WITH_SSH1
SSH_PACKET_CALLBACK(ssh_packet_publickey1);
#endif
#endif /* KEX_H_ */

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

@ -47,12 +47,16 @@ int packet_read(ssh_session session);
int packet_send1(ssh_session session) ;
void ssh_packet_set_default_callbacks1(ssh_session session);
SSH_PACKET_CALLBACK(ssh_packet_disconnect1);
SSH_PACKET_CALLBACK(ssh_packet_smsg_success1);
SSH_PACKET_CALLBACK(ssh_packet_smsg_failure1);
#endif
int packet_translate(ssh_session session);
/* TODO: remove it when packet_wait is stripped out from libssh */
#ifdef WITH_SSH1
int packet_wait(ssh_session session,int type,int blocking);
//int packet_wait(ssh_session session,int type,int blocking);
#endif
int packet_flush(ssh_session session, int enforce_blocking);

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

@ -191,6 +191,7 @@ int ssh_userauth1_offer_pubkey(ssh_session session, const char *username,
int ssh_userauth1_password(ssh_session session, const char *username,
const char *password);
#ifdef WITH_SSH1
/* channels1.c */
int channel_open_session1(ssh_channel channel);
int channel_request_pty_size1(ssh_channel channel, const char *terminal,
@ -198,9 +199,9 @@ int channel_request_pty_size1(ssh_channel channel, const char *terminal,
int channel_change_pty_size1(ssh_channel channel, int cols, int rows);
int channel_request_shell1(ssh_channel channel);
int channel_request_exec1(ssh_channel channel, const char *cmd);
int channel_handle1(ssh_session session, int type);
int channel_write1(ssh_channel channel, const void *data, int len);
#endif
/* match.c */
int match_hostname(const char *host, const char *pattern, unsigned int len);

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

@ -329,7 +329,8 @@ error:
}
/** @internal
* @brief parse a channel-related packet to resolve it to a ssh_channel.
* @brief parse a channel-related packet to resolve it to a ssh_channel. Works on SSH1
* sessions too.
* @param session current SSH session.
* @param packet buffer to parse packet from. The read pointer will be moved after
* the call.
@ -339,7 +340,11 @@ error:
static ssh_channel channel_from_msg(ssh_session session, ssh_buffer packet) {
ssh_channel channel;
uint32_t chan;
#ifdef WITH_SSH1
/* With SSH1, the channel is always the first one */
if(session->version==1)
return session->channels;
#endif
if (buffer_get_u32(packet, &chan) != sizeof(uint32_t)) {
ssh_set_error(session, SSH_FATAL,
"Getting channel from message: short read");
@ -1052,7 +1057,7 @@ void channel_set_blocking(ssh_channel channel, int blocking) {
/** @internal
* @brief handle a SSH_CHANNEL_SUCCESS packet and set the channel
* state.
* state. Also works on SSH1 sessions.
*/
SSH_PACKET_CALLBACK(ssh_packet_channel_success){
ssh_channel channel;
@ -1083,7 +1088,7 @@ SSH_PACKET_CALLBACK(ssh_packet_channel_success){
/** @internal
* @brief handle a SSH_CHANNEL_FAILURE packet and set the channel
* state.
* state. Also works on SSH1 sessions.
*/
SSH_PACKET_CALLBACK(ssh_packet_channel_failure){
ssh_channel channel;

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

@ -132,39 +132,45 @@ int channel_request_pty_size1(ssh_channel channel, const char *terminal, int col
int channel_change_pty_size1(ssh_channel channel, int cols, int rows) {
ssh_session session = channel->session;
if(channel->request_state != SSH_CHANNEL_REQ_STATE_NONE){
ssh_set_error(session,SSH_REQUEST_DENIED,"Wrong request state");
return SSH_ERROR;
}
if (buffer_add_u8(session->out_buffer, SSH_CMSG_WINDOW_SIZE) < 0 ||
buffer_add_u32(session->out_buffer, ntohl(rows)) < 0 ||
buffer_add_u32(session->out_buffer, ntohl(cols)) < 0 ||
buffer_add_u32(session->out_buffer, 0) < 0 ||
buffer_add_u32(session->out_buffer, 0) < 0) {
return -1;
return SSH_ERROR;
}
channel->request_state=SSH_CHANNEL_REQ_STATE_PENDING;
if (packet_send(session)) {
return -1;
return SSH_ERROR;
}
ssh_log(session, SSH_LOG_RARE, "Change pty size send");
if (packet_wait(session, SSH_SMSG_SUCCESS, 1) != SSH_OK) {
return -1;
ssh_log(session, SSH_LOG_PROTOCOL, "Change pty size send");
while(channel->request_state==SSH_CHANNEL_REQ_STATE_PENDING){
ssh_handle_packets(session,-1);
}
switch (session->in_packet.type) {
case SSH_SMSG_SUCCESS:
ssh_log(session, SSH_LOG_RARE, "pty size changed");
return 0;
case SSH_SMSG_FAILURE:
switch(channel->request_state){
case SSH_CHANNEL_REQ_STATE_ERROR:
case SSH_CHANNEL_REQ_STATE_PENDING:
case SSH_CHANNEL_REQ_STATE_NONE:
channel->request_state=SSH_CHANNEL_REQ_STATE_NONE;
return SSH_ERROR;
case SSH_CHANNEL_REQ_STATE_ACCEPTED:
channel->request_state=SSH_CHANNEL_REQ_STATE_NONE;
ssh_log(session, SSH_LOG_PROTOCOL, "pty size changed");
return SSH_OK;
case SSH_CHANNEL_REQ_STATE_DENIED:
channel->request_state=SSH_CHANNEL_REQ_STATE_NONE;
ssh_log(session, SSH_LOG_RARE, "pty size change denied");
ssh_set_error(session, SSH_REQUEST_DENIED, "pty size change denied");
return -1;
return SSH_ERROR;
}
// Not reached
return SSH_ERROR;
ssh_set_error(session, SSH_FATAL, "Received unexpected packet type %d",
session->in_packet.type);
return -1;
}
int channel_request_shell1(ssh_channel channel) {
@ -208,35 +214,37 @@ int channel_request_exec1(ssh_channel channel, const char *cmd) {
return 0;
}
static int channel_rcv_data1(ssh_session session, int is_stderr) {
SSH_PACKET_CALLBACK(ssh_packet_data1){
ssh_channel channel = session->channels;
ssh_string str = NULL;
str = buffer_get_ssh_string(session->in_buffer);
int is_stderr=(type==SSH_SMSG_STDOUT_DATA ? 0 : 1);
(void)user;
str = buffer_get_ssh_string(packet);
if (str == NULL) {
ssh_log(session, SSH_LOG_FUNCTIONS, "Invalid data packet !\n");
return -1;
return SSH_PACKET_USED;
}
ssh_log(session, SSH_LOG_RARE,
ssh_log(session, SSH_LOG_PROTOCOL,
"Adding %zu bytes data in %d",
string_len(str), is_stderr);
if (channel_default_bufferize(channel, string_data(str), string_len(str),
is_stderr) < 0) {
string_free(str);
return -1;
return SSH_PACKET_USED;
}
string_free(str);
return 0;
return SSH_PACKET_USED;
}
static int channel_rcv_close1(ssh_session session) {
SSH_PACKET_CALLBACK(ssh_packet_close1){
ssh_channel channel = session->channels;
uint32_t status;
buffer_get_u32(session->in_buffer, &status);
(void)type;
(void)user;
buffer_get_u32(packet, &status);
/*
* It's much more than a channel closing. spec says it's the last
* message sent by server (strange)
@ -246,41 +254,12 @@ static int channel_rcv_close1(ssh_session session) {
channel->open = 0;
channel->remote_eof = 1;
if (buffer_add_u8(session->out_buffer, SSH_CMSG_EXIT_CONFIRMATION) < 0) {
return -1;
}
buffer_add_u8(session->out_buffer, SSH_CMSG_EXIT_CONFIRMATION);
packet_send(session);
if (packet_send(session) != SSH_OK) {
return -1;
}
return 0;
return SSH_PACKET_USED;
}
int channel_handle1(ssh_session session, int type) {
ssh_log(session, SSH_LOG_RARE, "Channel_handle1(%d)", type);
switch (type) {
case SSH_SMSG_STDOUT_DATA:
if (channel_rcv_data1(session,0) < 0) {
return -1;
}
break;
case SSH_SMSG_STDERR_DATA:
if (channel_rcv_data1(session,1) < 0) {
return -1;
}
break;
case SSH_SMSG_EXITSTATUS:
if (channel_rcv_close1(session) < 0) {
return -1;
}
break;
default:
ssh_log(session, SSH_LOG_FUNCTIONS, "Unexpected message %d", type);
}
return 0;
}
int channel_write1(ssh_channel channel, const void *data, int len) {
ssh_session session = channel->session;

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

@ -601,7 +601,6 @@ void ssh_connection_callback(ssh_session session){
goto error;
set_status(session,0.6);
session->connected = 1;
session->session_state=SSH_SESSION_STATE_AUTHENTICATING;
break;
}
#endif

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

@ -597,7 +597,6 @@ static ssh_string encrypt_session_key(ssh_session session, ssh_public_key srvkey
return data1;
}
/* SSH-1 functions */
/* 2 SSH_SMSG_PUBLIC_KEY
*
@ -612,15 +611,16 @@ static ssh_string encrypt_session_key(ssh_session session, ssh_public_key srvkey
* 32-bit int supported_ciphers_mask
* 32-bit int supported_authentications_mask
*/
int ssh_get_kex1(ssh_session session) {
/**
* @brief Wait for a SSH_SMSG_PUBLIC_KEY and does the key exchange
*/
SSH_PACKET_CALLBACK(ssh_packet_publickey1){
ssh_string server_exp = NULL;
ssh_string server_mod = NULL;
ssh_string host_exp = NULL;
ssh_string host_mod = NULL;
ssh_string serverkey = NULL;
ssh_string hostkey = NULL;
ssh_string enc_session = NULL;
ssh_public_key srv = NULL;
ssh_public_key host = NULL;
uint32_t server_bits;
@ -628,45 +628,43 @@ int ssh_get_kex1(ssh_session session) {
uint32_t protocol_flags;
uint32_t supported_ciphers_mask;
uint32_t supported_authentications_mask;
ssh_string enc_session = NULL;
uint16_t bits;
int rc = -1;
int ko;
enter_function();
ssh_log(session, SSH_LOG_PROTOCOL, "Waiting for a SSH_SMSG_PUBLIC_KEY");
if (packet_wait(session, SSH_SMSG_PUBLIC_KEY, 1) != SSH_OK) {
leave_function();
return -1;
}
(void)type;
(void)user;
ssh_log(session, SSH_LOG_PROTOCOL, "Got a SSH_SMSG_PUBLIC_KEY");
if (buffer_get_data(session->in_buffer, session->server_kex.cookie, 8) != 8) {
if(session->session_state != SSH_SESSION_STATE_INITIAL_KEX){
ssh_set_error(session,SSH_FATAL,"SSH_KEXINIT received in wrong state");
goto error;
}
if (buffer_get_data(packet, session->server_kex.cookie, 8) != 8) {
ssh_set_error(session, SSH_FATAL, "Can't get cookie in buffer");
leave_function();
return -1;
goto error;
}
buffer_get_u32(session->in_buffer, &server_bits);
server_exp = buffer_get_mpint(session->in_buffer);
buffer_get_u32(packet, &server_bits);
server_exp = buffer_get_mpint(packet);
if (server_exp == NULL) {
goto error;
}
server_mod = buffer_get_mpint(session->in_buffer);
server_mod = buffer_get_mpint(packet);
if (server_mod == NULL) {
goto error;
}
buffer_get_u32(session->in_buffer, &host_bits);
host_exp = buffer_get_mpint(session->in_buffer);
buffer_get_u32(packet, &host_bits);
host_exp = buffer_get_mpint(packet);
if (host_exp == NULL) {
goto error;
}
host_mod = buffer_get_mpint(session->in_buffer);
host_mod = buffer_get_mpint(packet);
if (host_mod == NULL) {
goto error;
}
buffer_get_u32(session->in_buffer, &protocol_flags);
buffer_get_u32(session->in_buffer, &supported_ciphers_mask);
ko = buffer_get_u32(session->in_buffer, &supported_authentications_mask);
buffer_get_u32(packet, &protocol_flags);
buffer_get_u32(packet, &supported_ciphers_mask);
ko = buffer_get_u32(packet, &supported_authentications_mask);
if ((ko != sizeof(uint32_t)) || !host_mod || !host_exp
|| !server_mod || !server_exp) {
@ -722,7 +720,6 @@ int ssh_get_kex1(ssh_session session) {
ssh_set_error(session, SSH_FATAL, "Remote server doesn't accept 3DES");
goto error;
}
ssh_log(session, SSH_LOG_PROTOCOL, "Sending SSH_CMSG_SESSION_KEY");
if (buffer_add_u8(session->out_buffer, SSH_CMSG_SESSION_KEY) < 0) {
@ -756,7 +753,7 @@ int ssh_get_kex1(ssh_session session) {
if (buffer_add_u32(session->out_buffer, 0) < 0) {
goto error;
}
session->session_state=SSH_SESSION_STATE_KEXINIT_RECEIVED;
if (packet_send(session) != SSH_OK) {
goto error;
}
@ -768,19 +765,11 @@ int ssh_get_kex1(ssh_session session) {
session->current_crypto = session->next_crypto;
session->next_crypto = NULL;
ssh_log(session, SSH_LOG_PROTOCOL, "Waiting for a SSH_SMSG_SUCCESS");
if (packet_wait(session,SSH_SMSG_SUCCESS,1) != SSH_OK) {
char buffer[1024] = {0};
snprintf(buffer, sizeof(buffer),
"Key exchange failed: %s", ssh_get_error(session));
ssh_set_error(session, SSH_FATAL, "%s",buffer);
goto error;
}
ssh_log(session, SSH_LOG_PROTOCOL, "received SSH_SMSG_SUCCESS\n");
rc = 0;
goto end;
error:
session->session_state=SSH_SESSION_STATE_ERROR;
end:
string_free(host_mod);
string_free(host_exp);
string_free(server_mod);
@ -792,7 +781,31 @@ error:
publickey_free(host);
leave_function();
return rc;
return SSH_PACKET_USED;
}
int ssh_get_kex1(ssh_session session) {
int ret=SSH_ERROR;
enter_function();
ssh_log(session, SSH_LOG_PROTOCOL, "Waiting for a SSH_SMSG_PUBLIC_KEY");
/* Here the callback is called */
while(session->session_state==SSH_SESSION_STATE_INITIAL_KEX){
ssh_handle_packets(session,-1);
}
if(session->session_state==SSH_SESSION_STATE_ERROR)
goto error;
ssh_log(session, SSH_LOG_PROTOCOL, "Waiting for a SSH_SMSG_SUCCESS");
/* Waiting for SSH_SMSG_SUCCESS */
while(session->session_state==SSH_SESSION_STATE_KEXINIT_RECEIVED){
ssh_handle_packets(session,-1);
}
if(session->session_state==SSH_SESSION_STATE_ERROR)
goto error;
ssh_log(session, SSH_LOG_PROTOCOL, "received SSH_SMSG_SUCCESS\n");
ret=SSH_OK;
error:
leave_function();
return ret;
}
#endif /* WITH_SSH1 */

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

@ -26,13 +26,13 @@
#include "libssh/session.h"
#include "libssh/buffer.h"
#include "libssh/socket.h"
#include "libssh/kex.h"
#ifdef WITH_SSH1
ssh_packet_callback default_packet_handlers1[]= {
NULL, //SSH_MSG_NONE 0
NULL, //SSH_MSG_DISCONNECT 1
NULL, //SSH_SMSG_PUBLIC_KEY 2
ssh_packet_disconnect1, //SSH_MSG_DISCONNECT 1
ssh_packet_publickey1, //SSH_SMSG_PUBLIC_KEY 2
NULL, //SSH_CMSG_SESSION_KEY 3
NULL, //SSH_CMSG_USER 4
NULL, //SSH_CMSG_AUTH_RHOSTS 5
@ -44,17 +44,17 @@ ssh_packet_callback default_packet_handlers1[]= {
NULL, //SSH_CMSG_WINDOW_SIZE 11
NULL, //SSH_CMSG_EXEC_SHELL 12
NULL, //SSH_CMSG_EXEC_CMD 13
NULL, //SSH_SMSG_SUCCESS 14
NULL, //SSH_SMSG_FAILURE 15
ssh_packet_smsg_success1, //SSH_SMSG_SUCCESS 14
ssh_packet_smsg_failure1, //SSH_SMSG_FAILURE 15
NULL, //SSH_CMSG_STDIN_DATA 16
NULL, //SSH_SMSG_STDOUT_DATA 17
NULL, //SSH_SMSG_STDERR_DATA 18
ssh_packet_data1, //SSH_SMSG_STDOUT_DATA 17
ssh_packet_data1, //SSH_SMSG_STDERR_DATA 18
NULL, //SSH_CMSG_EOF 19
NULL, //SSH_SMSG_EXITSTATUS 20
NULL, //SSH_MSG_CHANNEL_OPEN_CONFIRMATION 21
NULL, //SSH_MSG_CHANNEL_OPEN_FAILURE 22
NULL, //SSH_MSG_CHANNEL_DATA 23
NULL, //SSH_MSG_CHANNEL_CLOSE 24
ssh_packet_close1, //SSH_MSG_CHANNEL_CLOSE 24
NULL, //SSH_MSG_CHANNEL_CLOSE_CONFIRMATION 25
NULL, //SSH_CMSG_X11_REQUEST_FORWARDING 26
NULL, //SSH_SMSG_X11_OPEN 27
@ -62,19 +62,11 @@ ssh_packet_callback default_packet_handlers1[]= {
NULL, //SSH_MSG_PORT_OPEN 29
NULL, //SSH_CMSG_AGENT_REQUEST_FORWARDING 30
NULL, //SSH_SMSG_AGENT_OPEN 31
NULL, //SSH_MSG_IGNORE 32
ssh_packet_ignore_callback, //SSH_MSG_IGNORE 32
NULL, //SSH_CMSG_EXIT_CONFIRMATION 33
NULL, //SSH_CMSG_X11_REQUEST_FORWARDING 34
NULL, //SSH_CMSG_AUTH_RHOSTS_RSA 35
NULL, //SSH_MSG_DEBUG 36
NULL, //SSH_CMSG_REQUEST_COMPRESSION 37
NULL, //SSH_CMSG_MAX_PACKET_SIZE 38
NULL, //SSH_CMSG_AUTH_TIS 39
NULL, //SSH_SMSG_AUTH_TIS_CHALLENGE 40
NULL, //SSH_CMSG_AUTH_TIS_RESPONSE 41
NULL, //SSH_CMSG_AUTH_KERBEROS 42
NULL, //SSH_SMSG_AUTH_KERBEROS_RESPONSE 43
NULL, //SSH_CMSG_HAVE_KERBEROS_TGT 44
ssh_packet_ignore_callback, //SSH_MSG_DEBUG 36
};
/** @internal
@ -316,37 +308,37 @@ error:
return rc; /* SSH_OK, AGAIN or ERROR */
}
static void packet_parse(ssh_session session) {
uint8_t type = session->in_packet.type;
if (session->version == 1) {
/* SSH-1 */
switch(type) {
case SSH_MSG_DISCONNECT:
SSH_PACKET_CALLBACK(ssh_packet_disconnect1){
(void)packet;
(void)user;
(void)type;
ssh_log(session, SSH_LOG_PACKET, "Received SSH_MSG_DISCONNECT");
ssh_set_error(session, SSH_FATAL, "Received SSH_MSG_DISCONNECT");
ssh_socket_close(session->socket);
session->alive = 0;
return;
case SSH_SMSG_STDOUT_DATA:
case SSH_SMSG_STDERR_DATA:
case SSH_SMSG_EXITSTATUS:
channel_handle1(session,type);
return;
case SSH_MSG_DEBUG:
case SSH_MSG_IGNORE:
break;
default:
ssh_log(session, SSH_LOG_PACKET,
"Unexpected message code %d", type);
}
return;
return SSH_PACKET_USED;
}
SSH_PACKET_CALLBACK(ssh_packet_smsg_success1){
if(session->session_state==SSH_SESSION_STATE_KEXINIT_RECEIVED){
session->session_state=SSH_SESSION_STATE_AUTHENTICATING;
return SSH_PACKET_USED;
} else {
return ssh_packet_channel_success(session,type,packet,user);
}
}
SSH_PACKET_CALLBACK(ssh_packet_smsg_failure1){
if(session->session_state==SSH_SESSION_STATE_KEXINIT_RECEIVED){
session->session_state=SSH_SESSION_STATE_ERROR;
ssh_set_error(session,SSH_FATAL,"Key exchange failed: received SSH_SMSG_FAILURE");
return SSH_PACKET_USED;
} else {
return ssh_packet_channel_failure(session,type,packet,user);
}
}
int packet_wait(ssh_session session, int type, int blocking) {
enter_function();
@ -363,24 +355,15 @@ int packet_wait(ssh_session session, int type, int blocking) {
session->in_packet.type);
switch (session->in_packet.type) {
case SSH_MSG_DISCONNECT:
packet_parse(session);
leave_function();
return SSH_ERROR;
case SSH_SMSG_STDOUT_DATA:
case SSH_SMSG_STDERR_DATA:
case SSH_SMSG_EXITSTATUS:
if (channel_handle1(session,type) < 0) {
leave_function();
return SSH_ERROR;
}
break;
case SSH_MSG_DEBUG:
case SSH_MSG_IGNORE:
ssh_packet_process(session,type);
break;
case SSH_SMSG_EXITSTATUS:
//This packet must be parsed too
break;
/* case SSH2_MSG_CHANNEL_CLOSE:
packet_parse(session);
break;;
*/
default:
if (type && (type != session->in_packet.type)) {
ssh_set_error(session, SSH_FATAL,