1
0
mirror of https://github.com/libssh2/libssh2.git synced 2025-08-08 19:02:07 +03:00

send custom channel requests

This commit is contained in:
Anders Borum
2021-12-02 15:58:24 +01:00
parent 5f7c32c8bf
commit 1615d0a867
3 changed files with 142 additions and 0 deletions

View File

@@ -816,6 +816,19 @@ LIBSSH2_API int libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel,
sizeof("subsystem") - 1, (subsystem), \ sizeof("subsystem") - 1, (subsystem), \
(unsigned int)strlen(subsystem)) (unsigned int)strlen(subsystem))
/* Deliver custom channel request.
data is allowed to be NULL when data_len is zero
While you can wait for reply this needs to be either success or failure as
there is no way to bring back anything else. */
LIBSSH2_API int libssh2_channel_custom_request(LIBSSH2_CHANNEL *channel,
int want_reply,
const char *request_type,
unsigned int request_type_len,
const char *data,
unsigned int data_len);
LIBSSH2_API ssize_t libssh2_channel_read_ex(LIBSSH2_CHANNEL *channel, LIBSSH2_API ssize_t libssh2_channel_read_ex(LIBSSH2_CHANNEL *channel,
int stream_id, char *buf, int stream_id, char *buf,
size_t buflen); size_t buflen);

View File

@@ -1273,6 +1273,125 @@ libssh2_channel_request_pty_size_ex(LIBSSH2_CHANNEL *channel, int width,
return rc; return rc;
} }
static int channel_custom_request(LIBSSH2_CHANNEL *channel, int want_reply,
const char *request_type, unsigned int request_type_len,
const char *data, unsigned int data_len) {
LIBSSH2_SESSION *session = channel->session;
static const unsigned char reply_codes[3] =
{ SSH_MSG_CHANNEL_SUCCESS, SSH_MSG_CHANNEL_FAILURE, 0 };
int rc;
if(channel->channel_custom_state == libssh2_NB_state_idle) {
/* 10 = packet_type(1) + channel(4) + request_type_len(4) + want_reply(1) */
channel->channel_custom_packet_len = 10 + request_type_len + data_len;
/* Zero the whole thing out */
memset(&channel->channel_custom_packet_requirev_state, 0,
sizeof(channel->channel_custom_packet_requirev_state));
_libssh2_debug(session, LIBSSH2_TRACE_CONN,
"custom request on channel %lu/%lu %.*s",
channel->local.id, channel->remote.id,
request_type_len, request_type);
/* make sure there isn't previous packet we would leak */
if(channel->channel_custom_packet) {
LIBSSH2_FREE(session, channel->channel_custom_packet);
}
/* allocate memory for packet */
channel->channel_custom_packet =
LIBSSH2_ALLOC(session, channel->channel_custom_packet_len);
if(!channel->channel_custom_packet) {
return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate memory for custom channel request");
}
/* compose packet */
unsigned char *s = channel->channel_custom_packet;
*(s++) = SSH_MSG_CHANNEL_REQUEST;
_libssh2_store_u32(&s, channel->remote.id);
_libssh2_store_str(&s, request_type, request_type_len);
*(s++) = want_reply;
if(data_len > 0) {
memcpy(s, data, data_len);
}
channel->channel_custom_state = libssh2_NB_state_created;
}
if(channel->channel_custom_state == libssh2_NB_state_created) {
rc = _libssh2_transport_send(session, channel->channel_custom_packet,
channel->channel_custom_packet_len,
NULL, 0);
if(rc == LIBSSH2_ERROR_EAGAIN) {
_libssh2_error(session, rc,
"Would block sending custom channel request");
return rc;
}
else if(rc) {
channel->channel_custom_state = libssh2_NB_state_idle;
return _libssh2_error(session, rc,
"Unable to send custom channel request packet");
}
_libssh2_htonu32(channel->channel_custom_local_channel, channel->local.id);
channel->channel_custom_state = libssh2_NB_state_sent;
}
if(channel->channel_custom_state == libssh2_NB_state_sent) {
if(!want_reply) {
channel->channel_custom_state = libssh2_NB_state_idle;
return 0;
}
unsigned char *data = 0;
size_t data_len = 0;
unsigned char code = 0;
rc = _libssh2_packet_requirev(
session, reply_codes, &data, &data_len, 1,
channel->channel_custom_local_channel,
4, &channel->channel_custom_packet_requirev_state);
if(rc == LIBSSH2_ERROR_EAGAIN) {
return rc;
}
else if(rc) {
channel->channel_custom_state = libssh2_NB_state_idle;
return _libssh2_error(session, LIBSSH2_ERROR_PROTO,
"Failed custom channel request");
}
if(data_len >= 1) {
code = data[0];
}
if(data) LIBSSH2_FREE(session, data);
channel->channel_custom_state = libssh2_NB_state_idle;
if(code == SSH_MSG_CHANNEL_SUCCESS) return 0;
return _libssh2_error(session, LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED,
"Failed custom channel request");
}
return _libssh2_error(session, LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED,
"Unable to complete custom channel request");
}
LIBSSH2_API int
libssh2_channel_custom_request(LIBSSH2_CHANNEL *channel, int want_reply,
const char *request_type, unsigned int request_type_len,
const char *data, unsigned int data_len) {
int rc;
if(!channel)
return LIBSSH2_ERROR_BAD_USE;
BLOCK_ADJUST(rc, channel->session,
channel_custom_request(channel, want_reply, request_type,
request_type_len, data, data_len));
return rc;
}
/* Keep this an even number */ /* Keep this an even number */
#define LIBSSH2_X11_RANDOM_COOKIE_LEN 32 #define LIBSSH2_X11_RANDOM_COOKIE_LEN 32
@@ -2792,6 +2911,9 @@ int _libssh2_channel_free(LIBSSH2_CHANNEL *channel)
if(channel->process_packet) { if(channel->process_packet) {
LIBSSH2_FREE(session, channel->process_packet); LIBSSH2_FREE(session, channel->process_packet);
} }
if(channel->channel_custom_packet) {
LIBSSH2_FREE(session, channel->channel_custom_packet);
}
LIBSSH2_FREE(session, channel); LIBSSH2_FREE(session, channel);

View File

@@ -419,6 +419,13 @@ struct _LIBSSH2_CHANNEL
unsigned char process_local_channel[4]; unsigned char process_local_channel[4];
packet_requirev_state_t process_packet_requirev_state; packet_requirev_state_t process_packet_requirev_state;
/* State variables used in libssh2_channel_custom_request() */
libssh2_nonblocking_states channel_custom_state;
unsigned char *channel_custom_packet;
size_t channel_custom_packet_len;
unsigned char channel_custom_local_channel[4];
packet_requirev_state_t channel_custom_packet_requirev_state;
/* State variables used in libssh2_channel_flush_ex() */ /* State variables used in libssh2_channel_flush_ex() */
libssh2_nonblocking_states flush_state; libssh2_nonblocking_states flush_state;
size_t flush_refund_bytes; size_t flush_refund_bytes;