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_open_fail);
|
||||||
SSH_PACKET_CALLBACK(ssh_packet_channel_success);
|
SSH_PACKET_CALLBACK(ssh_packet_channel_success);
|
||||||
SSH_PACKET_CALLBACK(ssh_packet_channel_failure);
|
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);
|
ssh_channel channel_new(ssh_session session);
|
||||||
int channel_default_bufferize(ssh_channel channel, void *data, int len,
|
int channel_default_bufferize(ssh_channel channel, void *data, int len,
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
#include "libssh/packet.h"
|
#include "libssh/packet.h"
|
||||||
#include "libssh/pcap.h"
|
#include "libssh/pcap.h"
|
||||||
#include "libssh/auth.h"
|
#include "libssh/auth.h"
|
||||||
|
#include "libssh/channels.h"
|
||||||
|
|
||||||
typedef struct ssh_kbdint_struct* ssh_kbdint;
|
typedef struct ssh_kbdint_struct* ssh_kbdint;
|
||||||
|
|
||||||
@@ -82,7 +83,7 @@ struct ssh_session_struct {
|
|||||||
int dh_handshake_state;
|
int dh_handshake_state;
|
||||||
enum ssh_auth_service_state_e auth_service_state;
|
enum ssh_auth_service_state_e auth_service_state;
|
||||||
enum ssh_auth_state_e auth_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.
|
ssh_string dh_server_signature; //information used by dh_handshake.
|
||||||
KEX server_kex;
|
KEX server_kex;
|
||||||
KEX client_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);
|
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,
|
static int global_request(ssh_session session, const char *request,
|
||||||
ssh_buffer buffer, int reply) {
|
ssh_buffer buffer, int reply) {
|
||||||
ssh_string req = NULL;
|
ssh_string req = NULL;
|
||||||
int rc = SSH_ERROR;
|
int rc = SSH_ERROR;
|
||||||
|
|
||||||
enter_function();
|
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);
|
req = string_from_char(request);
|
||||||
if (req == NULL) {
|
if (req == NULL) {
|
||||||
goto error;
|
goto error;
|
||||||
@@ -1517,6 +1574,7 @@ static int global_request(ssh_session session, const char *request,
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
string_free(req);
|
string_free(req);
|
||||||
|
req=NULL;
|
||||||
|
|
||||||
if (buffer != NULL) {
|
if (buffer != NULL) {
|
||||||
if (buffer_add_data(session->out_buffer, buffer_get(buffer),
|
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;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
session->global_req_state = SSH_CHANNEL_REQ_STATE_PENDING;
|
||||||
if (packet_send(session) != SSH_OK) {
|
if (packet_send(session) != SSH_OK) {
|
||||||
leave_function();
|
leave_function();
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssh_log(session, SSH_LOG_RARE,
|
ssh_log(session, SSH_LOG_PACKET,
|
||||||
"Sent a SSH_MSG_GLOBAL_REQUEST %s", request);
|
"Sent a SSH_MSG_GLOBAL_REQUEST %s", request);
|
||||||
if (reply == 0) {
|
if (reply == 0) {
|
||||||
|
session->global_req_state=SSH_CHANNEL_REQ_STATE_NONE;
|
||||||
leave_function();
|
leave_function();
|
||||||
return SSH_OK;
|
return SSH_OK;
|
||||||
}
|
}
|
||||||
|
while(session->global_req_state == SSH_CHANNEL_REQ_STATE_PENDING){
|
||||||
rc = packet_wait(session, SSH2_MSG_REQUEST_SUCCESS, 1);
|
rc=ssh_handle_packets(session);
|
||||||
if (rc == SSH_ERROR) {
|
if(rc==SSH_ERROR){
|
||||||
if (session->in_packet.type == SSH2_MSG_REQUEST_FAILURE) {
|
session->global_req_state = SSH_CHANNEL_REQ_STATE_ERROR;
|
||||||
ssh_log(session, SSH_LOG_PACKET,
|
break;
|
||||||
"%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);
|
|
||||||
}
|
}
|
||||||
} 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();
|
leave_function();
|
||||||
return rc;
|
return rc;
|
||||||
error:
|
error:
|
||||||
buffer_reinit(session->out_buffer);
|
|
||||||
string_free(req);
|
string_free(req);
|
||||||
|
|
||||||
leave_function();
|
leave_function();
|
||||||
return rc;
|
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, //62-79
|
||||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
||||||
NULL, //#define SSH2_MSG_GLOBAL_REQUEST 80
|
NULL, //#define SSH2_MSG_GLOBAL_REQUEST 80
|
||||||
NULL, //#define SSH2_MSG_REQUEST_SUCCESS 81
|
ssh_request_success, //#define SSH2_MSG_REQUEST_SUCCESS 81
|
||||||
NULL, //#define SSH2_MSG_REQUEST_FAILURE 82
|
ssh_request_denied, //#define SSH2_MSG_REQUEST_FAILURE 82
|
||||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, // 83-89
|
NULL, NULL, NULL, NULL, NULL, NULL, NULL, // 83-89
|
||||||
NULL, //#define SSH2_MSG_CHANNEL_OPEN 90
|
NULL, //#define SSH2_MSG_CHANNEL_OPEN 90
|
||||||
ssh_packet_channel_open_conf, //#define SSH2_MSG_CHANNEL_OPEN_CONFIRMATION 91
|
ssh_packet_channel_open_conf, //#define SSH2_MSG_CHANNEL_OPEN_CONFIRMATION 91
|
||||||
|
|||||||
Reference in New Issue
Block a user