mirror of
https://git.libssh.org/projects/libssh.git
synced 2025-11-30 13:01:23 +03:00
Add support for async global requests
Normally the infamous packet_wait() synchronous call is gone in all SSH2 client code.
This commit is contained in:
@@ -68,6 +68,8 @@ SSH_PACKET_CALLBACK(ssh_packet_channel_open_conf);
|
||||
SSH_PACKET_CALLBACK(ssh_packet_channel_open_fail);
|
||||
SSH_PACKET_CALLBACK(ssh_packet_channel_success);
|
||||
SSH_PACKET_CALLBACK(ssh_packet_channel_failure);
|
||||
SSH_PACKET_CALLBACK(ssh_request_success);
|
||||
SSH_PACKET_CALLBACK(ssh_request_denied);
|
||||
|
||||
ssh_channel channel_new(ssh_session session);
|
||||
int channel_default_bufferize(ssh_channel channel, void *data, int len,
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "libssh/packet.h"
|
||||
#include "libssh/pcap.h"
|
||||
#include "libssh/auth.h"
|
||||
#include "libssh/channels.h"
|
||||
|
||||
typedef struct ssh_kbdint_struct* ssh_kbdint;
|
||||
|
||||
@@ -82,7 +83,7 @@ struct ssh_session_struct {
|
||||
int dh_handshake_state;
|
||||
enum ssh_auth_service_state_e auth_service_state;
|
||||
enum ssh_auth_state_e auth_state;
|
||||
|
||||
enum ssh_channel_request_state_e global_req_state;
|
||||
ssh_string dh_server_signature; //information used by dh_handshake.
|
||||
KEX server_kex;
|
||||
KEX client_kex;
|
||||
|
||||
@@ -1499,13 +1499,70 @@ ssh_channel channel_accept_x11(ssh_channel channel, int timeout_ms) {
|
||||
return channel_accept(channel->session, SSH_CHANNEL_X11, timeout_ms);
|
||||
}
|
||||
|
||||
/** @internal
|
||||
* @brief handle a SSH_REQUEST_SUCCESS packet normally sent after a global request.
|
||||
*/
|
||||
SSH_PACKET_CALLBACK(ssh_request_success){
|
||||
(void)type;
|
||||
(void)user;
|
||||
(void)packet;
|
||||
enter_function();
|
||||
|
||||
ssh_log(session, SSH_LOG_PACKET,
|
||||
"Received SSH_REQUEST_SUCCESS");
|
||||
if(session->global_req_state != SSH_CHANNEL_REQ_STATE_PENDING){
|
||||
ssh_log(session, SSH_LOG_RARE, "SSH_REQUEST_SUCCESS received in incorrect state %d",
|
||||
session->global_req_state);
|
||||
} else {
|
||||
session->global_req_state=SSH_CHANNEL_REQ_STATE_ACCEPTED;
|
||||
}
|
||||
|
||||
leave_function();
|
||||
return SSH_PACKET_USED;
|
||||
}
|
||||
|
||||
/** @internal
|
||||
* @brief handle a SSH_REQUEST_DENIED packet normally sent after a global request.
|
||||
*/
|
||||
SSH_PACKET_CALLBACK(ssh_request_denied){
|
||||
(void)type;
|
||||
(void)user;
|
||||
(void)packet;
|
||||
enter_function();
|
||||
|
||||
ssh_log(session, SSH_LOG_PACKET,
|
||||
"Received SSH_REQUEST_FAILURE");
|
||||
if(session->global_req_state != SSH_CHANNEL_REQ_STATE_PENDING){
|
||||
ssh_log(session, SSH_LOG_RARE, "SSH_REQUEST_DENIED received in incorrect state %d",
|
||||
session->global_req_state);
|
||||
} else {
|
||||
session->global_req_state=SSH_CHANNEL_REQ_STATE_DENIED;
|
||||
}
|
||||
|
||||
leave_function();
|
||||
return SSH_PACKET_USED;
|
||||
|
||||
}
|
||||
|
||||
/** @brief sends a global request (needed for forward listening) and wait
|
||||
* for the result.
|
||||
* @param session ssh session handle
|
||||
* @param request the type of request (defined in RFC)
|
||||
* @param buffer additional data to put in packet
|
||||
* @param reply expect a reply from server
|
||||
* @return SSH_OK or SSH_ERROR
|
||||
*/
|
||||
static int global_request(ssh_session session, const char *request,
|
||||
ssh_buffer buffer, int reply) {
|
||||
ssh_string req = NULL;
|
||||
int rc = SSH_ERROR;
|
||||
|
||||
enter_function();
|
||||
|
||||
if(session->global_req_state != SSH_CHANNEL_REQ_STATE_NONE){
|
||||
ssh_set_error(session,SSH_FATAL,"Invalid state in start of global_request()");
|
||||
leave_function();
|
||||
return rc;
|
||||
}
|
||||
req = string_from_char(request);
|
||||
if (req == NULL) {
|
||||
goto error;
|
||||
@@ -1517,6 +1574,7 @@ static int global_request(ssh_session session, const char *request,
|
||||
goto error;
|
||||
}
|
||||
string_free(req);
|
||||
req=NULL;
|
||||
|
||||
if (buffer != NULL) {
|
||||
if (buffer_add_data(session->out_buffer, buffer_get(buffer),
|
||||
@@ -1524,40 +1582,50 @@ static int global_request(ssh_session session, const char *request,
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
session->global_req_state = SSH_CHANNEL_REQ_STATE_PENDING;
|
||||
if (packet_send(session) != SSH_OK) {
|
||||
leave_function();
|
||||
return rc;
|
||||
}
|
||||
|
||||
ssh_log(session, SSH_LOG_RARE,
|
||||
ssh_log(session, SSH_LOG_PACKET,
|
||||
"Sent a SSH_MSG_GLOBAL_REQUEST %s", request);
|
||||
if (reply == 0) {
|
||||
session->global_req_state=SSH_CHANNEL_REQ_STATE_NONE;
|
||||
leave_function();
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
rc = packet_wait(session, SSH2_MSG_REQUEST_SUCCESS, 1);
|
||||
if (rc == SSH_ERROR) {
|
||||
if (session->in_packet.type == SSH2_MSG_REQUEST_FAILURE) {
|
||||
ssh_log(session, SSH_LOG_PACKET,
|
||||
"%s channel request failed", request);
|
||||
ssh_set_error(session, SSH_REQUEST_DENIED,
|
||||
"Channel request %s failed", request);
|
||||
} else {
|
||||
ssh_log(session, SSH_LOG_RARE,
|
||||
"Received an unexpected %d message", session->in_packet.type);
|
||||
while(session->global_req_state == SSH_CHANNEL_REQ_STATE_PENDING){
|
||||
rc=ssh_handle_packets(session);
|
||||
if(rc==SSH_ERROR){
|
||||
session->global_req_state = SSH_CHANNEL_REQ_STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
ssh_log(session, SSH_LOG_RARE, "Received a SUCCESS");
|
||||
}
|
||||
switch(session->global_req_state){
|
||||
case SSH_CHANNEL_REQ_STATE_ACCEPTED:
|
||||
ssh_log(session, SSH_LOG_PROTOCOL, "Global request %s success",request);
|
||||
rc=SSH_OK;
|
||||
break;
|
||||
case SSH_CHANNEL_REQ_STATE_DENIED:
|
||||
ssh_log(session, SSH_LOG_PACKET,
|
||||
"Global request %s failed", request);
|
||||
ssh_set_error(session, SSH_REQUEST_DENIED,
|
||||
"Global request %s failed", request);
|
||||
rc=SSH_ERROR;
|
||||
break;
|
||||
case SSH_CHANNEL_REQ_STATE_ERROR:
|
||||
case SSH_CHANNEL_REQ_STATE_NONE:
|
||||
case SSH_CHANNEL_REQ_STATE_PENDING:
|
||||
rc=SSH_ERROR;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
leave_function();
|
||||
return rc;
|
||||
error:
|
||||
buffer_reinit(session->out_buffer);
|
||||
string_free(req);
|
||||
|
||||
leave_function();
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -78,8 +78,8 @@ ssh_packet_callback default_packet_handlers[]= {
|
||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, //62-79
|
||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
||||
NULL, //#define SSH2_MSG_GLOBAL_REQUEST 80
|
||||
NULL, //#define SSH2_MSG_REQUEST_SUCCESS 81
|
||||
NULL, //#define SSH2_MSG_REQUEST_FAILURE 82
|
||||
ssh_request_success, //#define SSH2_MSG_REQUEST_SUCCESS 81
|
||||
ssh_request_denied, //#define SSH2_MSG_REQUEST_FAILURE 82
|
||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, // 83-89
|
||||
NULL, //#define SSH2_MSG_CHANNEL_OPEN 90
|
||||
ssh_packet_channel_open_conf, //#define SSH2_MSG_CHANNEL_OPEN_CONFIRMATION 91
|
||||
|
||||
Reference in New Issue
Block a user