[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH] Re: Issues with channel callbacks
[Thread Prev] | [Thread Next]
- Subject: [PATCH] Re: Issues with channel callbacks
- From: Tilo Eckert <tilo.eckert@xxxxxxx>
- Reply-to: libssh@xxxxxxxxxx
- Date: Mon, 25 Mar 2019 15:41:21 +0100
- To: libssh@xxxxxxxxxx
Hi, some patches are attached that address the callback issues that I identified four weeks ago. The user-defined channel data callback is called repeatedly as long as there is data to consume or until the callback reports to be unable to consume more bytes. I introduced a new lastdata channel callback that is called repeatedly when a channel is about to be closed and there is unprocessed data left in the buffers from previous data callback invocations. Previously, it was just ignored and the channel was not closed properly as a result. My patches work around the channel->delayed_close issue. However, I still think it's legacy code and can be removed, which would also remove the risk of accidentally unclosed channels. There are also some new tests for the channel callbacks that make sure that they behave as intended and are called in the correct order. Regards Tilo Eckert Am 25.02.2019 um 11:18 schrieb Tilo Eckert: > Hi, > > I am experimenting with the ssh_event/connector APIs to remotely execute > commands and process the returned output via callbacks (to retain the > order of stdin and stderr messages as sent by the server). I used the > shell() and select_loop() functions from the ssh_client.c example as a > starting point. However, I replaced the stdout and stderr connectors > with callbacks like this: > >> ssh_connector connector_in; >> ssh_callbacks_init(&callback); >> callback.userdata = NULL; >> callback.channel_data_function = channel_data_callback; >> callback.channel_close_function = channel_close_callback; >> callback.channel_eof_function = channel_eof_callback; >> callback.channel_exit_signal_function = channel_exit_signal_callback; >> callback.channel_exit_status_function = channel_exit_status_callback; >> ssh_add_channel_callbacks(channel, &callback); > > I identified multiple issues with these callbacks during my experiments > and would appreciate some feedback on potential solutions: > > 1) If my data callback consumes less than the provided number of bytes > and the server closes the channel, the channel_rcv_close() callback in > channels.c will not actually set the channel state to closed, but set > channel->delayed_close = 1 instead because channel buffers are not > empty. This leads to an infinite loop in the main event loop: >> while (ssh_channel_is_open(channel)) { >> ssh_event_dopoll(event, 60000); >> } > Question: The assignment channel->delayed_close = 1 seems to be there > for a long time. Is there still any justification for it? The only thing > it seems to do is prevent writing to the channel, which also happens > when the channel is in closed state. If it was meant to delay setting > the closed state on the channel until remaining buffer contents have > been read via ssh_channel_read(), I would expect that the channel is set > to closed state in one of the read functions, but I cannot find such > code. That leads me to believe that channel->delayed_close can be safely > removed to fix the infinite loop. I might be wrong, though. > > 2) If the channel is being closed and my data callback did not consume > all data before, I do not get a chance to process the remaining data > because there simply exists no callback to handle this case. I would > like to introduce a new callback for this purpose which is executed in > channel_rcv_close() right before the close callback if there is data > remaining in the buffers. > > 3) My data callback is executed exactly once for every received channel > data packet. I think this should be changed to be more user-friendly: > The data callback should be executed repeatedly until it consumed all > available bytes or 0 (i.e. the callback signals that there is not enough > data to process). That would make it easier to implement custom protocol > handlers via callbacks. For example, a data callback that processes a > single line of text per call would no longer require a loop in the > callback function, leading to code that is easier to read. > > Regards, > Tilo Eckert >
From 825d3d7aed1ac13e6db9597b024294c2bb3a1902 Mon Sep 17 00:00:00 2001 From: Tilo Eckert <tilo.eckert@xxxxxxx> Date: Wed, 27 Feb 2019 16:59:51 +0100 Subject: [PATCH 1/7] channels: Rename variable to reflect its meaning Signed-off-by: Tilo Eckert <tilo.eckert@xxxxxxx> --- src/channels.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/channels.c b/src/channels.c index d339f732..0e28407e 100644 --- a/src/channels.c +++ b/src/channels.c @@ -483,7 +483,7 @@ SSH_PACKET_CALLBACK(channel_rcv_data){ ssh_buffer buf; size_t len; int is_stderr; - int rest; + int consumed; (void)user; if(type==SSH2_MSG_CHANNEL_DATA) @@ -560,17 +560,17 @@ SSH_PACKET_CALLBACK(channel_rcv_data){ if (ssh_buffer_get(buf) == NULL) { break; } - rest = ssh_callbacks_iterate_exec(channel_data_function, + consumed = ssh_callbacks_iterate_exec(channel_data_function, channel->session, channel, ssh_buffer_get(buf), ssh_buffer_get_len(buf), is_stderr); - if (rest > 0) { + if (consumed > 0) { if (channel->counter != NULL) { - channel->counter->in_bytes += rest; + channel->counter->in_bytes += consumed; } - ssh_buffer_pass_bytes(buf, rest); + ssh_buffer_pass_bytes(buf, consumed); } } ssh_callbacks_iterate_end(); -- 2.18.0
From 7be19741131f11bbc47a8565311949d189e455d3 Mon Sep 17 00:00:00 2001 From: Tilo Eckert <tilo.eckert@xxxxxxx> Date: Wed, 6 Mar 2019 11:03:17 +0100 Subject: [PATCH 2/7] channels: Reformat channel_rcv_close() Signed-off-by: Tilo Eckert <tilo.eckert@xxxxxxx> --- src/channels.c | 68 +++++++++++++++++++++++++------------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/src/channels.c b/src/channels.c index 0e28407e..8bd000cf 100644 --- a/src/channels.c +++ b/src/channels.c @@ -612,39 +612,39 @@ SSH_PACKET_CALLBACK(channel_rcv_eof) { } SSH_PACKET_CALLBACK(channel_rcv_close) { - ssh_channel channel; - (void)user; - (void)type; + ssh_channel channel; + (void)user; + (void)type; - channel = channel_from_msg(session,packet); - if (channel == NULL) { - SSH_LOG(SSH_LOG_FUNCTIONS, "%s", ssh_get_error(session)); + channel = channel_from_msg(session,packet); + if (channel == NULL) { + SSH_LOG(SSH_LOG_FUNCTIONS, "%s", ssh_get_error(session)); - return SSH_PACKET_USED; - } + return SSH_PACKET_USED; + } - SSH_LOG(SSH_LOG_PACKET, - "Received close on channel (%d:%d)", - channel->local_channel, - channel->remote_channel); - - if ((channel->stdout_buffer && - ssh_buffer_get_len(channel->stdout_buffer) > 0) || - (channel->stderr_buffer && - ssh_buffer_get_len(channel->stderr_buffer) > 0)) { - channel->delayed_close = 1; - } else { - channel->state = SSH_CHANNEL_STATE_CLOSED; - } - if (channel->remote_eof == 0) { - SSH_LOG(SSH_LOG_PACKET, - "Remote host not polite enough to send an eof before close"); - } - channel->remote_eof = 1; - /* - * The remote eof doesn't break things if there was still data into read - * buffer because the eof is ignored until the buffer is empty. - */ + SSH_LOG(SSH_LOG_PACKET, + "Received close on channel (%d:%d)", + channel->local_channel, + channel->remote_channel); + + if ((channel->stdout_buffer && + ssh_buffer_get_len(channel->stdout_buffer) > 0) || + (channel->stderr_buffer && + ssh_buffer_get_len(channel->stderr_buffer) > 0)) { + channel->delayed_close = 1; + } else { + channel->state = SSH_CHANNEL_STATE_CLOSED; + } + if (channel->remote_eof == 0) { + SSH_LOG(SSH_LOG_PACKET, + "Remote host not polite enough to send an eof before close"); + } + channel->remote_eof = 1; + /* + * The remote eof doesn't break things if there was still data into read + * buffer because the eof is ignored until the buffer is empty. + */ ssh_callbacks_execute_list(channel->callbacks, ssh_channel_callbacks, @@ -652,11 +652,11 @@ SSH_PACKET_CALLBACK(channel_rcv_close) { channel->session, channel); - channel->flags |= SSH_CHANNEL_FLAG_CLOSED_REMOTE; - if(channel->flags & SSH_CHANNEL_FLAG_FREED_LOCAL) - ssh_channel_do_free(channel); + channel->flags |= SSH_CHANNEL_FLAG_CLOSED_REMOTE; + if (channel->flags & SSH_CHANNEL_FLAG_FREED_LOCAL) + ssh_channel_do_free(channel); - return SSH_PACKET_USED; + return SSH_PACKET_USED; } SSH_PACKET_CALLBACK(channel_rcv_request) { -- 2.18.0
From f85717c7bf5910dae34a699200ec95869f275574 Mon Sep 17 00:00:00 2001 From: Tilo Eckert <tilo.eckert@xxxxxxx> Date: Fri, 15 Mar 2019 14:40:11 +0100 Subject: [PATCH 3/7] channels: Call channel data callback repeatedly The data callback is called in a loop until it returns 0 or until all data is consumed. If the callback reports more consumed bytes than were passed to it, all bytes are removed from the buffer. Signed-off-by: Tilo Eckert <tilo.eckert@xxxxxxx> --- include/libssh/callbacks.h | 2 ++ src/channels.c | 30 ++++++++++++++++++------------ 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/include/libssh/callbacks.h b/include/libssh/callbacks.h index 4e71b3b9..3a7914f0 100644 --- a/include/libssh/callbacks.h +++ b/include/libssh/callbacks.h @@ -783,6 +783,8 @@ struct ssh_channel_callbacks_struct { void *userdata; /** * This functions will be called when there is data available. + * The function is called repeatedly until all data is consumed or + * 0 is returned (i.e. no more data can be processed). */ ssh_channel_data_callback channel_data_function; /** diff --git a/src/channels.c b/src/channels.c index 8bd000cf..36f1f400 100644 --- a/src/channels.c +++ b/src/channels.c @@ -481,6 +481,7 @@ SSH_PACKET_CALLBACK(channel_rcv_data){ ssh_channel channel; ssh_string str; ssh_buffer buf; + uint32_t buflen; size_t len; int is_stderr; int consumed; @@ -557,21 +558,26 @@ SSH_PACKET_CALLBACK(channel_rcv_data){ ssh_callbacks_iterate(channel->callbacks, ssh_channel_callbacks, channel_data_function) { - if (ssh_buffer_get(buf) == NULL) { + if (buf == NULL) { break; } - consumed = ssh_callbacks_iterate_exec(channel_data_function, - channel->session, - channel, - ssh_buffer_get(buf), - ssh_buffer_get_len(buf), - is_stderr); - if (consumed > 0) { - if (channel->counter != NULL) { - channel->counter->in_bytes += consumed; + do { + buflen = ssh_buffer_get_len(buf); + consumed = ssh_callbacks_iterate_exec(channel_data_function, + channel->session, + channel, + ssh_buffer_get(buf), + buflen, + is_stderr); + if (consumed > 0) { + if (consumed > buflen) + consumed = buflen; + if (channel->counter != NULL) { + channel->counter->in_bytes += consumed; + } + ssh_buffer_pass_bytes(buf, consumed); } - ssh_buffer_pass_bytes(buf, consumed); - } + } while (consumed > 0 && consumed < buflen); } ssh_callbacks_iterate_end(); -- 2.18.0
From 983c85897b3f110b061ef9afac18be0d6b58b888 Mon Sep 17 00:00:00 2001 From: Tilo Eckert <tilo.eckert@xxxxxxx> Date: Fri, 15 Mar 2019 14:46:42 +0100 Subject: [PATCH 4/7] callbacks: Don't use i as variable name in macros Signed-off-by: Tilo Eckert <tilo.eckert@xxxxxxx> --- include/libssh/callbacks.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/include/libssh/callbacks.h b/include/libssh/callbacks.h index 3a7914f0..9b824063 100644 --- a/include/libssh/callbacks.h +++ b/include/libssh/callbacks.h @@ -451,16 +451,16 @@ typedef struct ssh_socket_callbacks_struct *ssh_socket_callbacks; * * @param va_args parameters to be passed */ -#define ssh_callbacks_execute_list(list, cbtype, c, ...) \ - do { \ - struct ssh_iterator *i = ssh_list_get_iterator(list); \ - cbtype cb; \ - while (i != NULL){ \ - cb = ssh_iterator_value(cbtype, i); \ - if (ssh_callbacks_exists(cb, c)) \ - cb-> c (__VA_ARGS__, cb->userdata); \ - i = i->next; \ - } \ +#define ssh_callbacks_execute_list(list, cbtype, c, ...) \ + do { \ + struct ssh_iterator *_cb_i = ssh_list_get_iterator(list); \ + cbtype cb; \ + while (_cb_i != NULL){ \ + cb = ssh_iterator_value(cbtype, _cb_i); \ + if (ssh_callbacks_exists(cb, c)) \ + cb-> c (__VA_ARGS__, cb->userdata); \ + _cb_i = _cb_i->next; \ + } \ } while(0) /** -- 2.18.0
From 0414cecd22c26119bc966c8043c92a75aded4e78 Mon Sep 17 00:00:00 2001 From: Tilo Eckert <tilo.eckert@xxxxxxx> Date: Fri, 15 Mar 2019 15:29:45 +0100 Subject: [PATCH 5/7] channels: Introduce new lastdata callback The lastdata callback is called when a channel is about to be closed. It gives the application developer a final chance to process the remaining buffered data, if it did not consume all bytes in a previous data callback invocation. The lastdata callback is called when an eof, exit-status, exit-signal or close message arrives for the channel, whatever comes first. The close message is the only mandatory message to close a channel. All others are optional. However, it does not make much sense if the lastdata callback is called _after_ the eof, exit-status or exit-signal callback. Therefore, it is called as early as reasonable. If a lastdata callback is set, the channel state is always set to closed even if not all data was consumed by the callback. Signed-off-by: Tilo Eckert <tilo.eckert@xxxxxxx> --- include/libssh/callbacks.h | 9 ++++++ src/channels.c | 58 +++++++++++++++++++++++++++++++++++--- 2 files changed, 63 insertions(+), 4 deletions(-) diff --git a/include/libssh/callbacks.h b/include/libssh/callbacks.h index 9b824063..3cabe9d9 100644 --- a/include/libssh/callbacks.h +++ b/include/libssh/callbacks.h @@ -787,6 +787,15 @@ struct ssh_channel_callbacks_struct { * 0 is returned (i.e. no more data can be processed). */ ssh_channel_data_callback channel_data_function; + /** + * This functions will be called when the channel was closed by the + * remote host and there is still data in the channel buffers that + * previous invocations of the channel_data_function were unable to + * process. This is the last chance to process any remaining data. + * The function is called repeatedly until all data is consumed or + * 0 is returned (i.e. no more data can be processed). + */ + ssh_channel_data_callback channel_lastdata_function; /** * This functions will be called when the channel has received an EOF. */ diff --git a/src/channels.c b/src/channels.c index 36f1f400..5e166da1 100644 --- a/src/channels.c +++ b/src/channels.c @@ -589,6 +589,46 @@ SSH_PACKET_CALLBACK(channel_rcv_data){ return SSH_PACKET_USED; } +static int ssh_callbacks_call_lastdata(ssh_channel channel) { + ssh_buffer buf[2]; + uint32_t buflen; + int consumed, i, called = 0; + + buf[0] = channel->stdout_buffer; + buf[1] = channel->stderr_buffer; + for (i = 0; i < sizeof(buf)/sizeof(*buf); i++) { + ssh_callbacks_iterate(channel->callbacks, + ssh_channel_callbacks, + channel_lastdata_function) { + buflen = ssh_buffer_get_len(buf[i]); + if (buf[i] == NULL || buflen == 0) { + break; + } + do { + buflen = ssh_buffer_get_len(buf[i]); + consumed = ssh_callbacks_iterate_exec(channel_lastdata_function, + channel->session, + channel, + ssh_buffer_get(buf[i]), + buflen, + buf[i] == channel->stderr_buffer); + if (consumed > 0) { + if (consumed > buflen) + consumed = buflen; + if (channel->counter != NULL) { + channel->counter->in_bytes += consumed; + } + ssh_buffer_pass_bytes(buf[i], consumed); + } + } while (consumed > 0 && consumed < buflen); + called = 1; + } + ssh_callbacks_iterate_end(); + } + + return called; +} + SSH_PACKET_CALLBACK(channel_rcv_eof) { ssh_channel channel; (void)user; @@ -608,6 +648,8 @@ SSH_PACKET_CALLBACK(channel_rcv_eof) { /* channel->remote_window = 0; */ channel->remote_eof = 1; + ssh_callbacks_call_lastdata(channel); + ssh_callbacks_execute_list(channel->callbacks, ssh_channel_callbacks, channel_eof_function, @@ -619,6 +661,8 @@ SSH_PACKET_CALLBACK(channel_rcv_eof) { SSH_PACKET_CALLBACK(channel_rcv_close) { ssh_channel channel; + int lastdata_called, stdout_hasdata, stderr_hasdata; + uint32_t stdout_buflen, stderr_buflen; (void)user; (void)type; @@ -634,10 +678,14 @@ SSH_PACKET_CALLBACK(channel_rcv_close) { channel->local_channel, channel->remote_channel); - if ((channel->stdout_buffer && - ssh_buffer_get_len(channel->stdout_buffer) > 0) || - (channel->stderr_buffer && - ssh_buffer_get_len(channel->stderr_buffer) > 0)) { + lastdata_called = ssh_callbacks_call_lastdata(channel); + + stdout_buflen = ssh_buffer_get_len(channel->stdout_buffer); + stderr_buflen = ssh_buffer_get_len(channel->stderr_buffer); + stdout_hasdata = (channel->stdout_buffer && stdout_buflen > 0); + stderr_hasdata = (channel->stderr_buffer && stderr_buflen > 0); + + if (!lastdata_called && (stdout_hasdata || stderr_hasdata)) { channel->delayed_close = 1; } else { channel->state = SSH_CHANNEL_STATE_CLOSED; @@ -696,6 +744,7 @@ SSH_PACKET_CALLBACK(channel_rcv_request) { } SSH_LOG(SSH_LOG_PACKET, "received exit-status %d", channel->exit_status); + ssh_callbacks_call_lastdata(channel); ssh_callbacks_execute_list(channel->callbacks, ssh_channel_callbacks, channel_exit_status_function, @@ -756,6 +805,7 @@ SSH_PACKET_CALLBACK(channel_rcv_request) { SSH_LOG(SSH_LOG_PACKET, "Remote connection closed by signal SIG %s %s", sig, core); + ssh_callbacks_call_lastdata(channel); ssh_callbacks_execute_list(channel->callbacks, ssh_channel_callbacks, channel_exit_signal_function, -- 2.18.0
From b68989f7ae838d66bd408a4314f2692f43d9e50c Mon Sep 17 00:00:00 2001 From: Tilo Eckert <tilo.eckert@xxxxxxx> Date: Fri, 15 Mar 2019 15:34:52 +0100 Subject: [PATCH 6/7] tests: Add channel callback tests for previous commits Signed-off-by: Tilo Eckert <tilo.eckert@xxxxxxx> --- tests/unittests/torture_channel.c | 432 +++++++++++++++++++++++++++++- 1 file changed, 431 insertions(+), 1 deletion(-) diff --git a/tests/unittests/torture_channel.c b/tests/unittests/torture_channel.c index c165c572..d5957cac 100644 --- a/tests/unittests/torture_channel.c +++ b/tests/unittests/torture_channel.c @@ -1,7 +1,8 @@ #include "config.h" #define LIBSSH_STATIC -#include <libssh/priv.h> +#include <libssh/libssh.h> +#include <libssh/misc.h> #include <sys/types.h> #include <sys/stat.h> @@ -39,10 +40,439 @@ static void torture_channel_select(void **state) close(fd); } +/* Defines for expected callback types */ +#define CALLBACK_DATA 1 +#define CALLBACK_LASTDATA 2 +#define CALLBACK_EXITSTATUS 3 +#define CALLBACK_EOF 4 +#define CALLBACK_CLOSE 5 + +/* Struct containing the expected callback calls */ +#define CB_EXPECT_ITEMS_MAX 8 +struct cb_expect_item { + int return_val; + uint32_t expect_type; + const void* expect_data; + uint32_t expect_len; + int expect_stderr; + int expect_exitstatus; +}; +struct cb_expect { + uint32_t pos; + uint32_t len; + struct cb_expect_item items[CB_EXPECT_ITEMS_MAX]; +}; + +/* Holds initial state for channel callback tests */ +struct cb_state { + ssh_session session; + uint32_t channel_id; + ssh_channel channel; + ssh_buffer packet; + struct ssh_channel_callbacks_struct callbacks; + struct cb_expect expect; +}; + +/* Helpers for managing expected callback calls */ + +static void cb_expect_init(struct cb_expect* expect) { + memset(expect, 0, sizeof(struct cb_expect)); +} + +static void cb_expect_done(struct cb_expect* expect) { + assert_int_equal(expect->pos, expect->len); +} + +static void cb_expect_add(struct cb_expect* expect, uint32_t type) { + assert_in_range(expect->len, 0, CB_EXPECT_ITEMS_MAX-1); + expect->items[expect->len].expect_type = type; + expect->len++; +} + +static void cb_expect_add_data(struct cb_expect* expect, uint32_t type, uint32_t len, const void* data, int stderr, int processed) { + assert_in_range(expect->len, 0, CB_EXPECT_ITEMS_MAX-1); + expect->items[expect->len].expect_type = type; + expect->items[expect->len].expect_data = data; + expect->items[expect->len].expect_len = len; + expect->items[expect->len].expect_stderr = stderr; + expect->items[expect->len].return_val = processed; + expect->len++; +} + +static void cb_expect_add_exitstatus(struct cb_expect* expect, uint32_t type, int exitstatus) { + assert_in_range(expect->len, 0, CB_EXPECT_ITEMS_MAX-1); + expect->items[expect->len].expect_type = type; + expect->items[expect->len].expect_exitstatus = exitstatus; + expect->len++; +} + +/* Channel callback verification functions */ + +static int rcv_data_cb(ssh_session session, ssh_channel channel, void *data, + uint32_t len, int is_stderr, void *userdata, uint32_t type) +{ + struct cb_expect* cb_data = (struct cb_expect*)userdata; + struct cb_expect_item* cb_item; + (void)session; + (void)channel; + + // was this callback call expected? + assert_in_range(cb_data->pos, 0, cb_data->len - 1); + cb_item = &cb_data->items[cb_data->pos]; + assert_int_equal(cb_item->expect_type, type); + + assert_int_equal(is_stderr, cb_item->expect_stderr); + assert_int_equal(len, cb_item->expect_len); + if (cb_item->expect_data != NULL) + assert_memory_equal(data, cb_item->expect_data, len); + + cb_data->pos++; + + return cb_item->return_val; +} + +static void rcv_type_cb(ssh_session session, ssh_channel channel, + void *userdata, uint32_t type) +{ + struct cb_expect* cb_data = (struct cb_expect*)userdata; + struct cb_expect_item* cb_item; + (void)session; + (void)channel; + + // was this callback call expected? + assert_in_range(cb_data->pos, 0, cb_data->len - 1); + cb_item = &cb_data->items[cb_data->pos]; + assert_int_equal(cb_item->expect_type, type); + + cb_data->pos++; +} + +static void rcv_exit_status_cb(ssh_session session, ssh_channel channel, + int exit_status, void *userdata) +{ + struct cb_expect* cb_data = (struct cb_expect*)userdata; + struct cb_expect_item* cb_item; + (void)session; + (void)channel; + + // was this callback call expected? + assert_in_range(cb_data->pos, 0, cb_data->len - 1); + cb_item = &cb_data->items[cb_data->pos]; + assert_int_equal(cb_item->expect_type, CALLBACK_EXITSTATUS); + + cb_data->pos++; +} + +static int rcv_packetdata_cb(ssh_session session, ssh_channel channel, void *data, + uint32_t len, int is_stderr, void *userdata) +{ + return rcv_data_cb(session, channel, data, len, is_stderr, userdata, + CALLBACK_DATA); +} +static int rcv_lastdata_cb(ssh_session session, ssh_channel channel, void *data, + uint32_t len, int is_stderr, void *userdata) +{ + return rcv_data_cb(session, channel, data, len, is_stderr, userdata, + CALLBACK_LASTDATA); +} + +static void rcv_eof_cb(ssh_session session, ssh_channel channel, void *userdata) +{ + rcv_type_cb(session, channel, userdata, CALLBACK_EOF); +} + +static void rcv_close_cb(ssh_session session, ssh_channel channel, void *userdata) +{ + rcv_type_cb(session, channel, userdata, CALLBACK_CLOSE); +} + +static int setup_channel_callbacks(void **state) +{ + struct cb_state *s; + struct ssh_iterator *it; + + s = calloc(1, sizeof(struct cb_state)); + assert_non_null(s); + + ssh_callbacks_init(&s->callbacks); + s->callbacks.channel_data_function = rcv_packetdata_cb; + s->callbacks.channel_exit_status_function = rcv_exit_status_cb; + s->callbacks.channel_lastdata_function = rcv_lastdata_cb; + s->callbacks.channel_eof_function = rcv_eof_cb; + s->callbacks.channel_close_function = rcv_close_cb; + s->callbacks.userdata = &s->expect; + + s->session = ssh_new(); + assert_non_null(s->session); + + s->channel = ssh_channel_new(s->session); + assert_non_null(s->channel); + + s->channel_id = 42; + s->channel->local_channel = s->channel_id; + s->channel->local_window = 999999999; + assert_ssh_return_code(s->session, ssh_add_channel_callbacks(s->channel, &s->callbacks)); + + it = ssh_list_find(s->channel->callbacks, &s->callbacks); + assert_non_null(it); + + s->packet = ssh_buffer_new(); + assert_non_null(s->packet); + + *state = s; + + return 0; +} + +static int teardown_channel_callbacks(void **state) +{ + struct cb_state *s = *state; + + ssh_channel_free(s->channel); + ssh_free(s->session); + free(*state); + + return 0; +} + +static void torture_channel_rcv_data(void **state) +{ + int rc; + struct cb_state *s = *state; + uint32_t data_len; + const char *data; + + // Simulate an incoming data packet on stdout + data = "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B"; + data_len = strlen(data); + + rc = ssh_buffer_pack(s->packet, "ds", s->channel_id, data); + assert_ssh_return_code(s->session, rc); + + cb_expect_init(&s->expect); + cb_expect_add_data(&s->expect, CALLBACK_DATA, data_len, data, 0, data_len-5); + cb_expect_add_data(&s->expect, CALLBACK_DATA, 5, data+data_len-5, 0, 3); + cb_expect_add_data(&s->expect, CALLBACK_DATA, 2, data+data_len-2, 0, 2); + + rc = channel_rcv_data(s->session, SSH2_MSG_CHANNEL_DATA, s->packet, NULL); + assert_ssh_return_code_equal(s->session, rc, SSH_PACKET_USED); + + cb_expect_done(&s->expect); + + // Simulate an incoming data packet on stderr + data = "\x11\x22\x33\x44\x55\x66\x77\x88\x99"; + data_len = strlen(data); + + rc = ssh_buffer_pack(s->packet, "dds", s->channel_id, 1, data); + assert_ssh_return_code(s->session, rc); + + cb_expect_init(&s->expect); + cb_expect_add_data(&s->expect, CALLBACK_DATA, data_len, data, 1, data_len); + + rc = channel_rcv_data(s->session, SSH2_MSG_CHANNEL_EXTENDED_DATA, + s->packet, NULL); + assert_ssh_return_code_equal(s->session, rc, SSH_PACKET_USED); + + cb_expect_done(&s->expect); +} + +static void torture_channel_rcv_eof(void **state) +{ + int rc; + struct cb_state *s = *state; + uint32_t data_len; + const char *data; + + // Simulate an incoming data packet on stdout which is not fully consumed + data = "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B"; + data_len = strlen(data); + + rc = ssh_buffer_pack(s->packet, "ds", s->channel_id, data); + assert_ssh_return_code(s->session, rc); + + cb_expect_init(&s->expect); + cb_expect_add_data(&s->expect, CALLBACK_DATA, data_len, data, 0, data_len-3); + cb_expect_add_data(&s->expect, CALLBACK_DATA, 3, data+data_len-3, 0, 0); + + rc = channel_rcv_data(s->session, SSH2_MSG_CHANNEL_DATA, s->packet, NULL); + assert_ssh_return_code_equal(s->session, rc, SSH_PACKET_USED); + + cb_expect_done(&s->expect); + + // Simulate an incoming EOF packet and check that the lastdata callback is called + rc = ssh_buffer_pack(s->packet, "d", s->channel_id); + assert_ssh_return_code(s->session, rc); + + cb_expect_init(&s->expect); + cb_expect_add_data(&s->expect, CALLBACK_LASTDATA, 3, data+data_len-3, 0, 2); + cb_expect_add_data(&s->expect, CALLBACK_LASTDATA, 1, data+data_len-1, 0, 1); + cb_expect_add(&s->expect, CALLBACK_EOF); + + rc = channel_rcv_eof(s->session, SSH2_MSG_CHANNEL_EOF, s->packet, NULL); + assert_ssh_return_code_equal(s->session, rc, SSH_PACKET_USED); + + cb_expect_done(&s->expect); +} + +static void torture_channel_rcv_data_eof(void **state) +{ + int rc; + struct cb_state *s = *state; + uint32_t data_len; + const char *data; + + // Simulate an incoming data packet on stdout which is not fully consumed + data = "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B"; + data_len = strlen(data); + + rc = ssh_buffer_pack(s->packet, "ds", s->channel_id, data); + assert_ssh_return_code(s->session, rc); + + cb_expect_init(&s->expect); + cb_expect_add_data(&s->expect, CALLBACK_DATA, data_len, data, 0, data_len-3); + cb_expect_add_data(&s->expect, CALLBACK_DATA, 3, data+data_len-3, 0, 0); + + rc = channel_rcv_data(s->session, SSH2_MSG_CHANNEL_DATA, s->packet, NULL); + assert_ssh_return_code_equal(s->session, rc, SSH_PACKET_USED); + + cb_expect_done(&s->expect); + + // Simulate an incoming EOF packet and check that the lastdata callback is called + rc = ssh_buffer_pack(s->packet, "d", s->channel_id); + assert_ssh_return_code(s->session, rc); + + cb_expect_init(&s->expect); + cb_expect_add_data(&s->expect, CALLBACK_LASTDATA, 3, data+data_len-3, 0, 2); + cb_expect_add_data(&s->expect, CALLBACK_LASTDATA, 1, data+data_len-1, 0, 1); + cb_expect_add(&s->expect, CALLBACK_EOF); + + rc = channel_rcv_eof(s->session, SSH2_MSG_CHANNEL_EOF, s->packet, NULL); + assert_ssh_return_code_equal(s->session, rc, SSH_PACKET_USED); + + cb_expect_done(&s->expect); +} + +static void torture_channel_rcv_close(void **state) +{ + int rc; + struct cb_state *s = *state; + + // Simulate an incoming close packet and check that no lastdata callback is called + rc = ssh_buffer_pack(s->packet, "d", s->channel_id); + assert_ssh_return_code(s->session, rc); + + cb_expect_init(&s->expect); + cb_expect_add(&s->expect, CALLBACK_CLOSE); + + rc = channel_rcv_close(s->session, SSH2_MSG_CHANNEL_CLOSE, s->packet, NULL); + assert_ssh_return_code_equal(s->session, rc, SSH_PACKET_USED); + + cb_expect_done(&s->expect); +} + +static void torture_channel_rcv_data_close(void **state) +{ + int rc; + struct cb_state *s = *state; + uint32_t data_len; + const char *data; + + // Simulate an incoming data packet on stdout which is not fully consumed + data = "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B"; + data_len = strlen(data); + + rc = ssh_buffer_pack(s->packet, "ds", s->channel_id, data); + assert_ssh_return_code(s->session, rc); + + cb_expect_init(&s->expect); + cb_expect_add_data(&s->expect, CALLBACK_DATA, data_len, data, 0, data_len-3); + cb_expect_add_data(&s->expect, CALLBACK_DATA, 3, data+data_len-3, 0, 0); + + rc = channel_rcv_data(s->session, SSH2_MSG_CHANNEL_DATA, s->packet, NULL); + assert_ssh_return_code_equal(s->session, rc, SSH_PACKET_USED); + + cb_expect_done(&s->expect); + + // Simulate an incoming close packet and check that the lastdata callback is called + rc = ssh_buffer_pack(s->packet, "d", s->channel_id); + assert_ssh_return_code(s->session, rc); + + cb_expect_init(&s->expect); + cb_expect_add_data(&s->expect, CALLBACK_LASTDATA, 3, data+data_len-3, 0, 3); + cb_expect_add(&s->expect, CALLBACK_CLOSE); + + rc = channel_rcv_close(s->session, SSH2_MSG_CHANNEL_CLOSE, s->packet, NULL); + assert_ssh_return_code_equal(s->session, rc, SSH_PACKET_USED); + + cb_expect_done(&s->expect); +} + +static void torture_channel_rcv_data_exit_eof_close(void **state) +{ + int rc; + struct cb_state *s = *state; + uint32_t data_len; + const char *data; + + // Simulate an incoming data packet on stdout which is not fully consumed + data = "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B"; + data_len = strlen(data); + + rc = ssh_buffer_pack(s->packet, "ds", s->channel_id, data); + assert_ssh_return_code(s->session, rc); + + cb_expect_init(&s->expect); + cb_expect_add_data(&s->expect, CALLBACK_DATA, data_len, data, 0, data_len-3); + cb_expect_add_data(&s->expect, CALLBACK_DATA, 3, data+data_len-3, 0, 0); + + rc = channel_rcv_data(s->session, SSH2_MSG_CHANNEL_DATA, s->packet, NULL); + assert_ssh_return_code_equal(s->session, rc, SSH_PACKET_USED); + + cb_expect_done(&s->expect); + + /* Simulate incoming exit-status, EOF and close packets (end of normal + * commmand channel) and check that the lastdata callback is called before + * the exit-status callback */ + cb_expect_init(&s->expect); + cb_expect_add_data(&s->expect, CALLBACK_LASTDATA, 3, data+data_len-3, 0, 3); + cb_expect_add_exitstatus(&s->expect, CALLBACK_EXITSTATUS, 23); + cb_expect_add(&s->expect, CALLBACK_EOF); + cb_expect_add(&s->expect, CALLBACK_CLOSE); + + rc = ssh_buffer_pack(s->packet, "dsbd", s->channel_id, "exit-status", 0, 23); + assert_ssh_return_code(s->session, rc); + rc = channel_rcv_request(s->session, SSH2_MSG_CHANNEL_REQUEST, s->packet, NULL); + assert_ssh_return_code_equal(s->session, rc, SSH_PACKET_USED); + + rc = ssh_buffer_pack(s->packet, "d", s->channel_id); + assert_ssh_return_code(s->session, rc); + rc = channel_rcv_eof(s->session, SSH2_MSG_CHANNEL_EOF, s->packet, NULL); + assert_ssh_return_code_equal(s->session, rc, SSH_PACKET_USED); + + rc = ssh_buffer_pack(s->packet, "d", s->channel_id); + assert_ssh_return_code(s->session, rc); + rc = channel_rcv_close(s->session, SSH2_MSG_CHANNEL_CLOSE, s->packet, NULL); + assert_ssh_return_code_equal(s->session, rc, SSH_PACKET_USED); + + cb_expect_done(&s->expect); +} + int torture_run_tests(void) { int rc; struct CMUnitTest tests[] = { cmocka_unit_test(torture_channel_select), + cmocka_unit_test_setup_teardown(torture_channel_rcv_data, + setup_channel_callbacks, teardown_channel_callbacks), + cmocka_unit_test_setup_teardown(torture_channel_rcv_eof, + setup_channel_callbacks, teardown_channel_callbacks), + cmocka_unit_test_setup_teardown(torture_channel_rcv_data_eof, + setup_channel_callbacks, teardown_channel_callbacks), + cmocka_unit_test_setup_teardown(torture_channel_rcv_close, + setup_channel_callbacks, teardown_channel_callbacks), + cmocka_unit_test_setup_teardown(torture_channel_rcv_data_close, + setup_channel_callbacks, teardown_channel_callbacks), + cmocka_unit_test_setup_teardown(torture_channel_rcv_data_exit_eof_close, + setup_channel_callbacks, teardown_channel_callbacks), }; ssh_init(); -- 2.18.0
From 09bc9b6951acfb42ca8a7ed6f5547df5a1f5ae80 Mon Sep 17 00:00:00 2001 From: Tilo Eckert <tilo.eckert@xxxxxxx> Date: Thu, 21 Mar 2019 14:47:17 +0100 Subject: [PATCH 7/7] channels: Reformat whole module Signed-off-by: Tilo Eckert <tilo.eckert@xxxxxxx> --- src/channels.c | 3757 ++++++++++++++++++++++++------------------------ 1 file changed, 1879 insertions(+), 1878 deletions(-) diff --git a/src/channels.c b/src/channels.c index 5e166da1..ab298c3b 100644 --- a/src/channels.c +++ b/src/channels.c @@ -129,7 +129,7 @@ ssh_channel ssh_channel_new(ssh_session session) * @return The new channel identifier. */ uint32_t ssh_channel_new_id(ssh_session session) { - return ++(session->maxchannel); + return ++(session->maxchannel); } /** @@ -139,60 +139,60 @@ uint32_t ssh_channel_new_id(ssh_session session) { * * Constructs the channel object. */ -SSH_PACKET_CALLBACK(ssh_packet_channel_open_conf){ - uint32_t channelid=0; - ssh_channel channel; - int rc; - (void)type; - (void)user; - - SSH_LOG(SSH_LOG_PACKET,"Received SSH2_MSG_CHANNEL_OPEN_CONFIRMATION"); - - rc = ssh_buffer_unpack(packet, "d", &channelid); - if (rc != SSH_OK) - goto error; - channel=ssh_channel_from_local(session,channelid); - if(channel==NULL){ - ssh_set_error(session, SSH_FATAL, - "Unknown channel id %lu", - (long unsigned int) channelid); - /* TODO: Set error marking in channel object */ +SSH_PACKET_CALLBACK(ssh_packet_channel_open_conf) { + uint32_t channelid = 0; + ssh_channel channel; + int rc; + (void)type; + (void)user; + + SSH_LOG(SSH_LOG_PACKET, "Received SSH2_MSG_CHANNEL_OPEN_CONFIRMATION"); + + rc = ssh_buffer_unpack(packet, "d", &channelid); + if (rc != SSH_OK) + goto error; + channel = ssh_channel_from_local(session, channelid); + if (channel == NULL) { + ssh_set_error(session, SSH_FATAL, + "Unknown channel id %lu", + (long unsigned int ) channelid); + /* TODO: Set error marking in channel object */ + + return SSH_PACKET_USED; + } + + rc = ssh_buffer_unpack(packet, "ddd", + &channel->remote_channel, + &channel->remote_window, + &channel->remote_maxpacket); + if (rc != SSH_OK) + goto error; + SSH_LOG(SSH_LOG_PROTOCOL, + "Received a CHANNEL_OPEN_CONFIRMATION for channel %d:%d", + channel->local_channel, + channel->remote_channel); + + if (channel->state != SSH_CHANNEL_STATE_OPENING) { + SSH_LOG(SSH_LOG_RARE, + "SSH2_MSG_CHANNEL_OPEN_CONFIRMATION received in incorrect " + "channel state %d", + channel->state); + goto error; + } + + SSH_LOG(SSH_LOG_PROTOCOL, + "Remote window : %lu, maxpacket : %lu", + (long unsigned int ) channel->remote_window, + (long unsigned int ) channel->remote_maxpacket); + + channel->state = SSH_CHANNEL_STATE_OPEN; + channel->flags &= ~SSH_CHANNEL_FLAG_NOT_BOUND; return SSH_PACKET_USED; - } - - rc = ssh_buffer_unpack(packet, "ddd", - &channel->remote_channel, - &channel->remote_window, - &channel->remote_maxpacket); - if (rc != SSH_OK) - goto error; - - SSH_LOG(SSH_LOG_PROTOCOL, - "Received a CHANNEL_OPEN_CONFIRMATION for channel %d:%d", - channel->local_channel, - channel->remote_channel); - - if (channel->state != SSH_CHANNEL_STATE_OPENING) { - SSH_LOG(SSH_LOG_RARE, - "SSH2_MSG_CHANNEL_OPEN_CONFIRMATION received in incorrect " - "channel state %d", - channel->state); - goto error; - } - - SSH_LOG(SSH_LOG_PROTOCOL, - "Remote window : %lu, maxpacket : %lu", - (long unsigned int) channel->remote_window, - (long unsigned int) channel->remote_maxpacket); - - channel->state = SSH_CHANNEL_STATE_OPEN; - channel->flags &= ~SSH_CHANNEL_FLAG_NOT_BOUND; - return SSH_PACKET_USED; error: - ssh_set_error(session, SSH_FATAL, "Invalid packet"); - return SSH_PACKET_USED; + ssh_set_error(session, SSH_FATAL, "Invalid packet"); + return SSH_PACKET_USED; } /** @@ -200,56 +200,55 @@ error: * * @brief Handle a SSH_CHANNEL_OPEN_FAILURE and set the state of the channel. */ -SSH_PACKET_CALLBACK(ssh_packet_channel_open_fail){ - - ssh_channel channel; - char *error = NULL; - uint32_t code; - int rc; - (void)user; - (void)type; - - channel=channel_from_msg(session,packet); - if(channel==NULL){ - SSH_LOG(SSH_LOG_RARE,"Invalid channel in packet"); +SSH_PACKET_CALLBACK(ssh_packet_channel_open_fail) { + ssh_channel channel; + char *error = NULL; + uint32_t code; + int rc; + (void)user; + (void)type; + + channel = channel_from_msg(session, packet); + if (channel == NULL) { + SSH_LOG(SSH_LOG_RARE, "Invalid channel in packet"); + return SSH_PACKET_USED; + } + + rc = ssh_buffer_unpack(packet, "ds", &code, &error); + if (rc != SSH_OK) { + ssh_set_error(session, SSH_FATAL, "Invalid packet"); + return SSH_PACKET_USED; + } + + if (channel->state != SSH_CHANNEL_STATE_OPENING) { + SSH_LOG(SSH_LOG_RARE, + "SSH2_MSG_CHANNEL_OPEN_FAILURE received in incorrect channel " + "state %d", + channel->state); + goto error; + } + + ssh_set_error(session, SSH_REQUEST_DENIED, + "Channel opening failure: channel %u error (%lu) %s", + channel->local_channel, + (long unsigned int ) code, + error); + SAFE_FREE(error); + channel->state = SSH_CHANNEL_STATE_OPEN_DENIED; return SSH_PACKET_USED; - } - - rc = ssh_buffer_unpack(packet, "ds", &code, &error); - if (rc != SSH_OK){ - ssh_set_error(session, SSH_FATAL, "Invalid packet"); - return SSH_PACKET_USED; - } - - if (channel->state != SSH_CHANNEL_STATE_OPENING) { - SSH_LOG(SSH_LOG_RARE, - "SSH2_MSG_CHANNEL_OPEN_FAILURE received in incorrect channel " - "state %d", - channel->state); - goto error; - } - - ssh_set_error(session, SSH_REQUEST_DENIED, - "Channel opening failure: channel %u error (%lu) %s", - channel->local_channel, - (long unsigned int) code, - error); - SAFE_FREE(error); - channel->state=SSH_CHANNEL_STATE_OPEN_DENIED; - return SSH_PACKET_USED; error: - ssh_set_error(session, SSH_FATAL, "Invalid packet"); - return SSH_PACKET_USED; + ssh_set_error(session, SSH_FATAL, "Invalid packet"); + return SSH_PACKET_USED; } -static int ssh_channel_open_termination(void *c){ - ssh_channel channel = (ssh_channel) c; - if (channel->state != SSH_CHANNEL_STATE_OPENING || - channel->session->session_state == SSH_SESSION_STATE_ERROR) - return 1; - else - return 0; +static int ssh_channel_open_termination(void *c) { + ssh_channel channel = (ssh_channel)c; + if (channel->state != SSH_CHANNEL_STATE_OPENING || + channel->session->session_state == SSH_SESSION_STATE_ERROR) + return 1; + else + return 0; } /** @@ -271,91 +270,92 @@ static int ssh_channel_open_termination(void *c){ * @param[in] payload The buffer containing additional payload for the query. */ static int channel_open(ssh_channel channel, const char *type, int window, - int maxpacket, ssh_buffer payload) { - ssh_session session = channel->session; - int err=SSH_ERROR; - int rc; - - switch(channel->state){ - case SSH_CHANNEL_STATE_NOT_OPEN: - break; - case SSH_CHANNEL_STATE_OPENING: - goto pending; - case SSH_CHANNEL_STATE_OPEN: - case SSH_CHANNEL_STATE_CLOSED: - case SSH_CHANNEL_STATE_OPEN_DENIED: - goto end; - default: - ssh_set_error(session,SSH_FATAL,"Bad state in channel_open: %d",channel->state); - } - channel->local_channel = ssh_channel_new_id(session); - channel->local_maxpacket = maxpacket; - channel->local_window = window; - - SSH_LOG(SSH_LOG_PROTOCOL, - "Creating a channel %d with %d window and %d max packet", - channel->local_channel, window, maxpacket); - - rc = ssh_buffer_pack(session->out_buffer, - "bsddd", - SSH2_MSG_CHANNEL_OPEN, - type, - channel->local_channel, - channel->local_window, - channel->local_maxpacket); - if (rc != SSH_OK){ - ssh_set_error_oom(session); - return err; - } + int maxpacket, ssh_buffer payload) +{ + ssh_session session = channel->session; + int err = SSH_ERROR; + int rc; + + switch (channel->state) { + case SSH_CHANNEL_STATE_NOT_OPEN: + break; + case SSH_CHANNEL_STATE_OPENING: + goto pending; + case SSH_CHANNEL_STATE_OPEN: + case SSH_CHANNEL_STATE_CLOSED: + case SSH_CHANNEL_STATE_OPEN_DENIED: + goto end; + default: + ssh_set_error(session, SSH_FATAL, "Bad state in channel_open: %d", channel->state); + } + channel->local_channel = ssh_channel_new_id(session); + channel->local_maxpacket = maxpacket; + channel->local_window = window; + + SSH_LOG(SSH_LOG_PROTOCOL, + "Creating a channel %d with %d window and %d max packet", + channel->local_channel, window, maxpacket); + + rc = ssh_buffer_pack(session->out_buffer, + "bsddd", + SSH2_MSG_CHANNEL_OPEN, + type, + channel->local_channel, + channel->local_window, + channel->local_maxpacket); + if (rc != SSH_OK) { + ssh_set_error_oom(session); + return err; + } - if (payload != NULL) { - if (ssh_buffer_add_buffer(session->out_buffer, payload) < 0) { - ssh_set_error_oom(session); + if (payload != NULL) { + if (ssh_buffer_add_buffer(session->out_buffer, payload) < 0) { + ssh_set_error_oom(session); - return err; + return err; + } } - } - channel->state = SSH_CHANNEL_STATE_OPENING; - if (ssh_packet_send(session) == SSH_ERROR) { + channel->state = SSH_CHANNEL_STATE_OPENING; + if (ssh_packet_send(session) == SSH_ERROR) { - return err; - } + return err; + } - SSH_LOG(SSH_LOG_PACKET, - "Sent a SSH_MSG_CHANNEL_OPEN type %s for channel %d", - type, channel->local_channel); + SSH_LOG(SSH_LOG_PACKET, + "Sent a SSH_MSG_CHANNEL_OPEN type %s for channel %d", + type, channel->local_channel); pending: - /* wait until channel is opened by server */ - err = ssh_handle_packets_termination(session, - SSH_TIMEOUT_DEFAULT, - ssh_channel_open_termination, - channel); - - if (session->session_state == SSH_SESSION_STATE_ERROR) - err = SSH_ERROR; + /* wait until channel is opened by server */ + err = ssh_handle_packets_termination(session, + SSH_TIMEOUT_DEFAULT, + ssh_channel_open_termination, + channel); + + if (session->session_state == SSH_SESSION_STATE_ERROR) + err = SSH_ERROR; end: - if(channel->state == SSH_CHANNEL_STATE_OPEN) - err=SSH_OK; + if (channel->state == SSH_CHANNEL_STATE_OPEN) + err = SSH_OK; - return err; + return err; } /* return channel with corresponding local id, or NULL if not found */ ssh_channel ssh_channel_from_local(ssh_session session, uint32_t id) { - struct ssh_iterator *it; - ssh_channel channel; + struct ssh_iterator *it; + ssh_channel channel; - for (it = ssh_list_get_iterator(session->channels); it != NULL ; it=it->next) { - channel = ssh_iterator_value(ssh_channel, it); - if (channel == NULL) { - continue; - } - if (channel->local_channel == id) { - return channel; + for (it = ssh_list_get_iterator(session->channels); it != NULL; it = it->next) { + channel = ssh_iterator_value(ssh_channel, it); + if (channel == NULL) { + continue; + } + if (channel->local_channel == id) { + return channel; + } } - } - return NULL; + return NULL; } /** @@ -366,47 +366,47 @@ ssh_channel ssh_channel_from_local(ssh_session session, uint32_t id) { * @param minimumsize The minimum acceptable size for the new window. */ static int grow_window(ssh_session session, ssh_channel channel, int minimumsize) { - uint32_t new_window = minimumsize > WINDOWBASE ? minimumsize : WINDOWBASE; - int rc; + uint32_t new_window = minimumsize > WINDOWBASE ? minimumsize : WINDOWBASE; + int rc; + + if (new_window <= channel->local_window) { + SSH_LOG(SSH_LOG_PROTOCOL, + "growing window (channel %d:%d) to %d bytes : not needed (%d bytes)", + channel->local_channel, channel->remote_channel, new_window, + channel->local_window); + + return SSH_OK; + } + /* WINDOW_ADJUST packet needs a relative increment rather than an absolute + * value, so we give here the missing bytes needed to reach new_window + */ + rc = ssh_buffer_pack(session->out_buffer, + "bdd", + SSH2_MSG_CHANNEL_WINDOW_ADJUST, + channel->remote_channel, + new_window - channel->local_window); + if (rc != SSH_OK) { + ssh_set_error_oom(session); + goto error; + } + + if (ssh_packet_send(session) == SSH_ERROR) { + goto error; + } - if(new_window <= channel->local_window){ SSH_LOG(SSH_LOG_PROTOCOL, - "growing window (channel %d:%d) to %d bytes : not needed (%d bytes)", - channel->local_channel, channel->remote_channel, new_window, - channel->local_window); + "growing window (channel %d:%d) to %d bytes", + channel->local_channel, + channel->remote_channel, + new_window); + + channel->local_window = new_window; return SSH_OK; - } - /* WINDOW_ADJUST packet needs a relative increment rather than an absolute - * value, so we give here the missing bytes needed to reach new_window - */ - rc = ssh_buffer_pack(session->out_buffer, - "bdd", - SSH2_MSG_CHANNEL_WINDOW_ADJUST, - channel->remote_channel, - new_window - channel->local_window); - if (rc != SSH_OK) { - ssh_set_error_oom(session); - goto error; - } - - if (ssh_packet_send(session) == SSH_ERROR) { - goto error; - } - - SSH_LOG(SSH_LOG_PROTOCOL, - "growing window (channel %d:%d) to %d bytes", - channel->local_channel, - channel->remote_channel, - new_window); - - channel->local_window = new_window; - - return SSH_OK; error: - ssh_buffer_reinit(session->out_buffer); + ssh_buffer_reinit(session->out_buffer); - return SSH_ERROR; + return SSH_ERROR; } /** @@ -423,240 +423,242 @@ error: * unknown or the packet is invalid. */ static ssh_channel channel_from_msg(ssh_session session, ssh_buffer packet) { - ssh_channel channel; - uint32_t chan; - int rc; - - rc = ssh_buffer_unpack(packet,"d",&chan); - if (rc != SSH_OK) { - ssh_set_error(session, SSH_FATAL, - "Getting channel from message: short read"); - return NULL; - } + ssh_channel channel; + uint32_t chan; + int rc; - channel = ssh_channel_from_local(session, chan); - if (channel == NULL) { - ssh_set_error(session, SSH_FATAL, - "Server specified invalid channel %lu", - (long unsigned int) chan); - } + rc = ssh_buffer_unpack(packet, "d", &chan); + if (rc != SSH_OK) { + ssh_set_error(session, SSH_FATAL, + "Getting channel from message: short read"); + return NULL; + } - return channel; + channel = ssh_channel_from_local(session, chan); + if (channel == NULL) { + ssh_set_error(session, SSH_FATAL, + "Server specified invalid channel %lu", + (long unsigned int ) chan); + } + + return channel; } SSH_PACKET_CALLBACK(channel_rcv_change_window) { - ssh_channel channel; - uint32_t bytes; - int rc; - (void)user; - (void)type; - - channel = channel_from_msg(session,packet); - if (channel == NULL) { - SSH_LOG(SSH_LOG_FUNCTIONS, "%s", ssh_get_error(session)); - } - - rc = ssh_buffer_unpack(packet, "d", &bytes); - if (channel == NULL || rc != SSH_OK) { - SSH_LOG(SSH_LOG_PACKET, - "Error getting a window adjust message: invalid packet"); + ssh_channel channel; + uint32_t bytes; + int rc; + (void)user; + (void)type; - return SSH_PACKET_USED; - } + channel = channel_from_msg(session, packet); + if (channel == NULL) { + SSH_LOG(SSH_LOG_FUNCTIONS, "%s", ssh_get_error(session)); + } + + rc = ssh_buffer_unpack(packet, "d", &bytes); + if (channel == NULL || rc != SSH_OK) { + SSH_LOG(SSH_LOG_PACKET, + "Error getting a window adjust message: invalid packet"); - SSH_LOG(SSH_LOG_PROTOCOL, - "Adding %d bytes to channel (%d:%d) (from %d bytes)", - bytes, - channel->local_channel, - channel->remote_channel, - channel->remote_window); + return SSH_PACKET_USED; + } + + SSH_LOG(SSH_LOG_PROTOCOL, + "Adding %d bytes to channel (%d:%d) (from %d bytes)", + bytes, + channel->local_channel, + channel->remote_channel, + channel->remote_window); - channel->remote_window += bytes; + channel->remote_window += bytes; - return SSH_PACKET_USED; + return SSH_PACKET_USED; } /* is_stderr is set to 1 if the data are extended, ie stderr */ -SSH_PACKET_CALLBACK(channel_rcv_data){ - ssh_channel channel; - ssh_string str; - ssh_buffer buf; - uint32_t buflen; - size_t len; - int is_stderr; - int consumed; - (void)user; - - if(type==SSH2_MSG_CHANNEL_DATA) - is_stderr=0; - else - is_stderr=1; +SSH_PACKET_CALLBACK(channel_rcv_data) { + ssh_channel channel; + ssh_string str; + ssh_buffer buf; + uint32_t buflen; + size_t len; + int is_stderr; + int consumed; + (void)user; - channel = channel_from_msg(session,packet); - if (channel == NULL) { - SSH_LOG(SSH_LOG_FUNCTIONS, - "%s", ssh_get_error(session)); + if (type == SSH2_MSG_CHANNEL_DATA) + is_stderr = 0; + else + is_stderr = 1; - return SSH_PACKET_USED; - } + channel = channel_from_msg(session, packet); + if (channel == NULL) { + SSH_LOG(SSH_LOG_FUNCTIONS, + "%s", ssh_get_error(session)); - if (is_stderr) { - uint32_t ignore; - /* uint32 data type code. we can ignore it */ - ssh_buffer_get_u32(packet, &ignore); - } + return SSH_PACKET_USED; + } - str = ssh_buffer_get_ssh_string(packet); - if (str == NULL) { - SSH_LOG(SSH_LOG_PACKET, "Invalid data packet!"); + if (is_stderr) { + uint32_t ignore; + /* uint32 data type code. we can ignore it */ + ssh_buffer_get_u32(packet, &ignore); + } + + str = ssh_buffer_get_ssh_string(packet); + if (str == NULL) { + SSH_LOG(SSH_LOG_PACKET, "Invalid data packet!"); + + return SSH_PACKET_USED; + } + len = ssh_string_len(str); + + SSH_LOG(SSH_LOG_PACKET, + "Channel receiving %" PRIdS " bytes data in %d (local win=%d remote win=%d)", + len, + is_stderr, + channel->local_window, + channel->remote_window); + + /* What shall we do in this case? Let's accept it anyway */ + if (len > channel->local_window) { + SSH_LOG(SSH_LOG_RARE, + "Data packet too big for our window(%" PRIdS " vs %d)", + len, + channel->local_window); + } + + if (channel_default_bufferize(channel, ssh_string_data(str), len, + is_stderr) < 0) { + ssh_string_free(str); + + return SSH_PACKET_USED; + } + + if (len <= channel->local_window) { + channel->local_window -= len; + } else { + channel->local_window = 0; /* buggy remote */ + } + + SSH_LOG(SSH_LOG_PACKET, + "Channel windows are now (local win=%d remote win=%d)", + channel->local_window, + channel->remote_window); - return SSH_PACKET_USED; - } - len = ssh_string_len(str); - - SSH_LOG(SSH_LOG_PACKET, - "Channel receiving %" PRIdS " bytes data in %d (local win=%d remote win=%d)", - len, - is_stderr, - channel->local_window, - channel->remote_window); - - /* What shall we do in this case? Let's accept it anyway */ - if (len > channel->local_window) { - SSH_LOG(SSH_LOG_RARE, - "Data packet too big for our window(%" PRIdS " vs %d)", - len, - channel->local_window); - } - - if (channel_default_bufferize(channel, ssh_string_data(str), len, - is_stderr) < 0) { ssh_string_free(str); + if (is_stderr) { + buf = channel->stderr_buffer; + } else { + buf = channel->stdout_buffer; + } + + ssh_callbacks_iterate(channel->callbacks, + ssh_channel_callbacks, + channel_data_function) + { + if (buf == NULL) { + break; + } + do { + buflen = ssh_buffer_get_len(buf); + consumed = ssh_callbacks_iterate_exec(channel_data_function, + channel->session, + channel, + ssh_buffer_get(buf), + buflen, + is_stderr); + if (consumed > 0) { + if (consumed > buflen) + consumed = buflen; + if (channel->counter != NULL) { + channel->counter->in_bytes += consumed; + } + ssh_buffer_pass_bytes(buf, consumed); + } + } while (consumed > 0 && consumed < buflen); + } + ssh_callbacks_iterate_end(); + + if (channel->local_window + ssh_buffer_get_len(buf) < WINDOWLIMIT) { + if (grow_window(session, channel, 0) < 0) { + return -1; + } + } return SSH_PACKET_USED; - } - - if (len <= channel->local_window) { - channel->local_window -= len; - } else { - channel->local_window = 0; /* buggy remote */ - } - - SSH_LOG(SSH_LOG_PACKET, - "Channel windows are now (local win=%d remote win=%d)", - channel->local_window, - channel->remote_window); - - ssh_string_free(str); - - if (is_stderr) { - buf = channel->stderr_buffer; - } else { - buf = channel->stdout_buffer; - } - - ssh_callbacks_iterate(channel->callbacks, - ssh_channel_callbacks, - channel_data_function) { - if (buf == NULL) { - break; - } - do { - buflen = ssh_buffer_get_len(buf); - consumed = ssh_callbacks_iterate_exec(channel_data_function, - channel->session, - channel, - ssh_buffer_get(buf), - buflen, - is_stderr); - if (consumed > 0) { - if (consumed > buflen) - consumed = buflen; - if (channel->counter != NULL) { - channel->counter->in_bytes += consumed; - } - ssh_buffer_pass_bytes(buf, consumed); - } - } while (consumed > 0 && consumed < buflen); - } - ssh_callbacks_iterate_end(); - - if (channel->local_window + ssh_buffer_get_len(buf) < WINDOWLIMIT) { - if (grow_window(session, channel, 0) < 0) { - return -1; - } - } - return SSH_PACKET_USED; } static int ssh_callbacks_call_lastdata(ssh_channel channel) { - ssh_buffer buf[2]; - uint32_t buflen; - int consumed, i, called = 0; - - buf[0] = channel->stdout_buffer; - buf[1] = channel->stderr_buffer; - for (i = 0; i < sizeof(buf)/sizeof(*buf); i++) { - ssh_callbacks_iterate(channel->callbacks, - ssh_channel_callbacks, - channel_lastdata_function) { - buflen = ssh_buffer_get_len(buf[i]); - if (buf[i] == NULL || buflen == 0) { - break; - } - do { - buflen = ssh_buffer_get_len(buf[i]); - consumed = ssh_callbacks_iterate_exec(channel_lastdata_function, - channel->session, - channel, - ssh_buffer_get(buf[i]), - buflen, - buf[i] == channel->stderr_buffer); - if (consumed > 0) { - if (consumed > buflen) - consumed = buflen; - if (channel->counter != NULL) { - channel->counter->in_bytes += consumed; - } - ssh_buffer_pass_bytes(buf[i], consumed); - } - } while (consumed > 0 && consumed < buflen); - called = 1; - } - ssh_callbacks_iterate_end(); - } + ssh_buffer buf[2]; + uint32_t buflen; + int consumed, i, called = 0; + + buf[0] = channel->stdout_buffer; + buf[1] = channel->stderr_buffer; + for (i = 0; i < sizeof(buf) / sizeof(*buf); i++) { + ssh_callbacks_iterate(channel->callbacks, + ssh_channel_callbacks, + channel_lastdata_function) + { + buflen = ssh_buffer_get_len(buf[i]); + if (buf[i] == NULL || buflen == 0) { + break; + } + do { + buflen = ssh_buffer_get_len(buf[i]); + consumed = ssh_callbacks_iterate_exec(channel_lastdata_function, + channel->session, + channel, + ssh_buffer_get(buf[i]), + buflen, + buf[i] == channel->stderr_buffer); + if (consumed > 0) { + if (consumed > buflen) + consumed = buflen; + if (channel->counter != NULL) { + channel->counter->in_bytes += consumed; + } + ssh_buffer_pass_bytes(buf[i], consumed); + } + } while (consumed > 0 && consumed < buflen); + called = 1; + } + ssh_callbacks_iterate_end(); + } - return called; + return called; } SSH_PACKET_CALLBACK(channel_rcv_eof) { - ssh_channel channel; - (void)user; - (void)type; + ssh_channel channel; + (void)user; + (void)type; - channel = channel_from_msg(session,packet); - if (channel == NULL) { - SSH_LOG(SSH_LOG_FUNCTIONS, "%s", ssh_get_error(session)); + channel = channel_from_msg(session, packet); + if (channel == NULL) { + SSH_LOG(SSH_LOG_FUNCTIONS, "%s", ssh_get_error(session)); - return SSH_PACKET_USED; - } + return SSH_PACKET_USED; + } - SSH_LOG(SSH_LOG_PACKET, - "Received eof on channel (%d:%d)", - channel->local_channel, - channel->remote_channel); - /* channel->remote_window = 0; */ - channel->remote_eof = 1; + SSH_LOG(SSH_LOG_PACKET, + "Received eof on channel (%d:%d)", + channel->local_channel, + channel->remote_channel); + /* channel->remote_window = 0; */ + channel->remote_eof = 1; - ssh_callbacks_call_lastdata(channel); + ssh_callbacks_call_lastdata(channel); - ssh_callbacks_execute_list(channel->callbacks, - ssh_channel_callbacks, - channel_eof_function, - channel->session, - channel); + ssh_callbacks_execute_list(channel->callbacks, + ssh_channel_callbacks, + channel_eof_function, + channel->session, + channel); - return SSH_PACKET_USED; + return SSH_PACKET_USED; } SSH_PACKET_CALLBACK(channel_rcv_close) { @@ -666,7 +668,7 @@ SSH_PACKET_CALLBACK(channel_rcv_close) { (void)user; (void)type; - channel = channel_from_msg(session,packet); + channel = channel_from_msg(session, packet); if (channel == NULL) { SSH_LOG(SSH_LOG_FUNCTIONS, "%s", ssh_get_error(session)); @@ -714,28 +716,28 @@ SSH_PACKET_CALLBACK(channel_rcv_close) { } SSH_PACKET_CALLBACK(channel_rcv_request) { - ssh_channel channel; - char *request=NULL; + ssh_channel channel; + char *request = NULL; uint8_t status; int rc; - (void)user; - (void)type; - - channel = channel_from_msg(session,packet); - if (channel == NULL) { - SSH_LOG(SSH_LOG_FUNCTIONS,"%s", ssh_get_error(session)); - return SSH_PACKET_USED; - } - - rc = ssh_buffer_unpack(packet, "sb", - &request, - &status); - if (rc != SSH_OK) { - SSH_LOG(SSH_LOG_PACKET, "Invalid MSG_CHANNEL_REQUEST"); - return SSH_PACKET_USED; - } - - if (strcmp(request,"exit-status") == 0) { + (void)user; + (void)type; + + channel = channel_from_msg(session, packet); + if (channel == NULL) { + SSH_LOG(SSH_LOG_FUNCTIONS, "%s", ssh_get_error(session)); + return SSH_PACKET_USED; + } + + rc = ssh_buffer_unpack(packet, "sb", + &request, + &status); + if (rc != SSH_OK) { + SSH_LOG(SSH_LOG_PACKET, "Invalid MSG_CHANNEL_REQUEST"); + return SSH_PACKET_USED; + } + + if (strcmp(request, "exit-status") == 0) { SAFE_FREE(request); rc = ssh_buffer_unpack(packet, "d", &channel->exit_status); if (rc != SSH_OK) { @@ -752,61 +754,61 @@ SSH_PACKET_CALLBACK(channel_rcv_request) { channel, channel->exit_status); - return SSH_PACKET_USED; - } + return SSH_PACKET_USED; + } - if (strcmp(request,"signal") == 0) { + if (strcmp(request, "signal") == 0) { char *sig = NULL; - SAFE_FREE(request); - SSH_LOG(SSH_LOG_PACKET, "received signal"); + SAFE_FREE(request); + SSH_LOG(SSH_LOG_PACKET, "received signal"); - rc = ssh_buffer_unpack(packet, "s", &sig); - if (rc != SSH_OK) { - SSH_LOG(SSH_LOG_PACKET, "Invalid MSG_CHANNEL_REQUEST"); - return SSH_PACKET_USED; - } + rc = ssh_buffer_unpack(packet, "s", &sig); + if (rc != SSH_OK) { + SSH_LOG(SSH_LOG_PACKET, "Invalid MSG_CHANNEL_REQUEST"); + return SSH_PACKET_USED; + } - SSH_LOG(SSH_LOG_PACKET, - "Remote connection sent a signal SIG %s", sig); + SSH_LOG(SSH_LOG_PACKET, + "Remote connection sent a signal SIG %s", sig); ssh_callbacks_execute_list(channel->callbacks, ssh_channel_callbacks, channel_signal_function, channel->session, channel, sig); - SAFE_FREE(sig); - - return SSH_PACKET_USED; - } - - if (strcmp(request, "exit-signal") == 0) { - const char *core = "(core dumped)"; - char *sig = NULL; - char *errmsg = NULL; - char *lang = NULL; - uint8_t core_dumped; - - SAFE_FREE(request); - - rc = ssh_buffer_unpack(packet, "sbss", - &sig, /* signal name */ - &core_dumped, /* core dumped */ - &errmsg, /* error message */ - &lang); - if (rc != SSH_OK) { - SSH_LOG(SSH_LOG_PACKET, "Invalid MSG_CHANNEL_REQUEST"); - return SSH_PACKET_USED; - } - - if (core_dumped == 0) { - core = ""; - } - - SSH_LOG(SSH_LOG_PACKET, - "Remote connection closed by signal SIG %s %s", sig, core); - ssh_callbacks_call_lastdata(channel); - ssh_callbacks_execute_list(channel->callbacks, + SAFE_FREE(sig); + + return SSH_PACKET_USED; + } + + if (strcmp(request, "exit-signal") == 0) { + const char *core = "(core dumped)"; + char *sig = NULL; + char *errmsg = NULL; + char *lang = NULL; + uint8_t core_dumped; + + SAFE_FREE(request); + + rc = ssh_buffer_unpack(packet, "sbss", + &sig, /* signal name */ + &core_dumped, /* core dumped */ + &errmsg, /* error message */ + &lang); + if (rc != SSH_OK) { + SSH_LOG(SSH_LOG_PACKET, "Invalid MSG_CHANNEL_REQUEST"); + return SSH_PACKET_USED; + } + + if (core_dumped == 0) { + core = ""; + } + + SSH_LOG(SSH_LOG_PACKET, + "Remote connection closed by signal SIG %s %s", sig, core); + ssh_callbacks_call_lastdata(channel); + ssh_callbacks_execute_list(channel->callbacks, ssh_channel_callbacks, channel_exit_signal_function, channel->session, @@ -818,50 +820,50 @@ SSH_PACKET_CALLBACK(channel_rcv_request) { SAFE_FREE(lang); SAFE_FREE(errmsg); - SAFE_FREE(sig); - - return SSH_PACKET_USED; - } - if(strcmp(request,"keepalive@xxxxxxxxxxx")==0){ - SAFE_FREE(request); - SSH_LOG(SSH_LOG_PROTOCOL,"Responding to Openssh's keepalive"); - - rc = ssh_buffer_pack(session->out_buffer, - "bd", - SSH2_MSG_CHANNEL_FAILURE, - channel->remote_channel); - if (rc != SSH_OK) { - return SSH_PACKET_USED; - } - ssh_packet_send(session); - - return SSH_PACKET_USED; - } - - if (strcmp(request, "auth-agent-req@xxxxxxxxxxx") == 0) { - SAFE_FREE(request); - SSH_LOG(SSH_LOG_PROTOCOL, "Received an auth-agent-req request"); - ssh_callbacks_execute_list(channel->callbacks, - ssh_channel_callbacks, - channel_auth_agent_req_function, - channel->session, - channel); + SAFE_FREE(sig); - return SSH_PACKET_USED; - } + return SSH_PACKET_USED; + } + if (strcmp(request, "keepalive@xxxxxxxxxxx") == 0) { + SAFE_FREE(request); + SSH_LOG(SSH_LOG_PROTOCOL, "Responding to Openssh's keepalive"); + + rc = ssh_buffer_pack(session->out_buffer, + "bd", + SSH2_MSG_CHANNEL_FAILURE, + channel->remote_channel); + if (rc != SSH_OK) { + return SSH_PACKET_USED; + } + ssh_packet_send(session); + + return SSH_PACKET_USED; + } + + if (strcmp(request, "auth-agent-req@xxxxxxxxxxx") == 0) { + SAFE_FREE(request); + SSH_LOG(SSH_LOG_PROTOCOL, "Received an auth-agent-req request"); + ssh_callbacks_execute_list(channel->callbacks, + ssh_channel_callbacks, + channel_auth_agent_req_function, + channel->session, + channel); + + return SSH_PACKET_USED; + } #ifdef WITH_SERVER - /* If we are here, that means we have a request that is not in the understood - * client requests. That means we need to create a ssh message to be passed - * to the user code handling ssh messages - */ - ssh_message_handle_channel_request(session,channel,packet,request,status); + /* If we are here, that means we have a request that is not in the understood + * client requests. That means we need to create a ssh message to be passed + * to the user code handling ssh messages + */ + ssh_message_handle_channel_request(session, channel, packet, request, status); #else SSH_LOG(SSH_LOG_WARNING, "Unhandled channel request %s", request); #endif - - SAFE_FREE(request); - return SSH_PACKET_USED; + SAFE_FREE(request); + + return SSH_PACKET_USED; } /* @@ -870,58 +872,57 @@ SSH_PACKET_CALLBACK(channel_rcv_request) { * * FIXME is the window changed? */ -int channel_default_bufferize(ssh_channel channel, void *data, int len, - int is_stderr) { - ssh_session session; - - if(channel == NULL) { - return -1; - } - - session = channel->session; - - if(data == NULL) { - ssh_set_error_invalid(session); - return -1; - } +int channel_default_bufferize(ssh_channel channel, void *data, int len, int is_stderr) { + ssh_session session; - SSH_LOG(SSH_LOG_PACKET, - "placing %d bytes into channel buffer (stderr=%d)", len, is_stderr); - if (is_stderr == 0) { - /* stdout */ - if (channel->stdout_buffer == NULL) { - channel->stdout_buffer = ssh_buffer_new(); - if (channel->stdout_buffer == NULL) { - ssh_set_error_oom(session); + if (channel == NULL) { return -1; - } } - if (ssh_buffer_add_data(channel->stdout_buffer, data, len) < 0) { - ssh_set_error_oom(session); - ssh_buffer_free(channel->stdout_buffer); - channel->stdout_buffer = NULL; - return -1; - } - } else { - /* stderr */ - if (channel->stderr_buffer == NULL) { - channel->stderr_buffer = ssh_buffer_new(); - if (channel->stderr_buffer == NULL) { - ssh_set_error_oom(session); + session = channel->session; + + if (data == NULL) { + ssh_set_error_invalid(session); return -1; - } } - if (ssh_buffer_add_data(channel->stderr_buffer, data, len) < 0) { - ssh_set_error_oom(session); - ssh_buffer_free(channel->stderr_buffer); - channel->stderr_buffer = NULL; - return -1; + SSH_LOG(SSH_LOG_PACKET, + "placing %d bytes into channel buffer (stderr=%d)", len, is_stderr); + if (is_stderr == 0) { + /* stdout */ + if (channel->stdout_buffer == NULL) { + channel->stdout_buffer = ssh_buffer_new(); + if (channel->stdout_buffer == NULL) { + ssh_set_error_oom(session); + return -1; + } + } + + if (ssh_buffer_add_data(channel->stdout_buffer, data, len) < 0) { + ssh_set_error_oom(session); + ssh_buffer_free(channel->stdout_buffer); + channel->stdout_buffer = NULL; + return -1; + } + } else { + /* stderr */ + if (channel->stderr_buffer == NULL) { + channel->stderr_buffer = ssh_buffer_new(); + if (channel->stderr_buffer == NULL) { + ssh_set_error_oom(session); + return -1; + } + } + + if (ssh_buffer_add_data(channel->stderr_buffer, data, len) < 0) { + ssh_set_error_oom(session); + ssh_buffer_free(channel->stderr_buffer); + channel->stderr_buffer = NULL; + return -1; + } } - } - return 0; + return 0; } /** @@ -940,15 +941,15 @@ int channel_default_bufferize(ssh_channel channel, void *data, int len, * @see ssh_channel_request_exec() */ int ssh_channel_open_session(ssh_channel channel) { - if(channel == NULL) { - return SSH_ERROR; - } + if (channel == NULL) { + return SSH_ERROR; + } - return channel_open(channel, - "session", - CHANNEL_INITIAL_WINDOW, - CHANNEL_MAX_PACKET, - NULL); + return channel_open(channel, + "session", + CHANNEL_INITIAL_WINDOW, + CHANNEL_MAX_PACKET, + NULL); } /** @@ -966,16 +967,16 @@ int ssh_channel_open_session(ssh_channel channel) { * * @see ssh_channel_open_forward() */ -int ssh_channel_open_auth_agent(ssh_channel channel){ - if(channel == NULL) { - return SSH_ERROR; - } +int ssh_channel_open_auth_agent(ssh_channel channel) { + if (channel == NULL) { + return SSH_ERROR; + } - return channel_open(channel, - "auth-agent@xxxxxxxxxxx", - CHANNEL_INITIAL_WINDOW, - CHANNEL_MAX_PACKET, - NULL); + return channel_open(channel, + "auth-agent@xxxxxxxxxxx", + CHANNEL_INITIAL_WINDOW, + CHANNEL_MAX_PACKET, + NULL); } @@ -1005,51 +1006,51 @@ int ssh_channel_open_auth_agent(ssh_channel channel){ * use channel_read and channel_write for this. */ int ssh_channel_open_forward(ssh_channel channel, const char *remotehost, - int remoteport, const char *sourcehost, int localport) { - ssh_session session; - ssh_buffer payload = NULL; - ssh_string str = NULL; - int rc = SSH_ERROR; - - if(channel == NULL) { - return rc; - } - - session = channel->session; - - if(remotehost == NULL || sourcehost == NULL) { - ssh_set_error_invalid(session); - return rc; - } - - payload = ssh_buffer_new(); - if (payload == NULL) { - ssh_set_error_oom(session); - goto error; - } - - rc = ssh_buffer_pack(payload, - "sdsd", - remotehost, - remoteport, - sourcehost, - localport); - if (rc != SSH_OK) { - ssh_set_error_oom(session); - goto error; - } - - rc = channel_open(channel, - "direct-tcpip", - CHANNEL_INITIAL_WINDOW, - CHANNEL_MAX_PACKET, - payload); + int remoteport, const char *sourcehost, int localport) { + ssh_session session; + ssh_buffer payload = NULL; + ssh_string str = NULL; + int rc = SSH_ERROR; + + if (channel == NULL) { + return rc; + } + + session = channel->session; + + if (remotehost == NULL || sourcehost == NULL) { + ssh_set_error_invalid(session); + return rc; + } + + payload = ssh_buffer_new(); + if (payload == NULL) { + ssh_set_error_oom(session); + goto error; + } + + rc = ssh_buffer_pack(payload, + "sdsd", + remotehost, + remoteport, + sourcehost, + localport); + if (rc != SSH_OK) { + ssh_set_error_oom(session); + goto error; + } + + rc = channel_open(channel, + "direct-tcpip", + CHANNEL_INITIAL_WINDOW, + CHANNEL_MAX_PACKET, + payload); error: - ssh_buffer_free(payload); - ssh_string_free(str); + ssh_buffer_free(payload); + ssh_string_free(str); - return rc; + return rc; } @@ -1073,20 +1074,20 @@ void ssh_channel_free(ssh_channel channel) bool send_close = false; switch (channel->state) { - case SSH_CHANNEL_STATE_OPEN: - send_close = true; - break; - case SSH_CHANNEL_STATE_CLOSED: - if (channel->flags & SSH_CHANNEL_FLAG_CLOSED_REMOTE) { + case SSH_CHANNEL_STATE_OPEN: send_close = true; - } - if (channel->flags & SSH_CHANNEL_FLAG_CLOSED_LOCAL) { + break; + case SSH_CHANNEL_STATE_CLOSED: + if (channel->flags & SSH_CHANNEL_FLAG_CLOSED_REMOTE) { + send_close = true; + } + if (channel->flags & SSH_CHANNEL_FLAG_CLOSED_LOCAL) { + send_close = false; + } + break; + default: send_close = false; - } - break; - default: - send_close = false; - break; + break; } if (send_close) { @@ -1101,7 +1102,7 @@ void ssh_channel_free(ssh_channel channel) * the user closed it. */ if ((channel->flags & SSH_CHANNEL_FLAG_CLOSED_REMOTE) || - (channel->flags & SSH_CHANNEL_FLAG_NOT_BOUND)) { + (channel->flags & SSH_CHANNEL_FLAG_NOT_BOUND)) { ssh_channel_do_free(channel); } } @@ -1182,9 +1183,9 @@ int ssh_channel_send_eof(ssh_channel channel) rc = ssh_packet_send(session); SSH_LOG(SSH_LOG_PACKET, - "Sent a EOF on client channel (%d:%d)", - channel->local_channel, - channel->remote_channel); + "Sent a EOF on client channel (%d:%d)", + channel->local_channel, + channel->remote_channel); if (rc != SSH_OK) { goto error; } @@ -1272,22 +1273,22 @@ error: } /* this termination function waits for a window growing condition */ -static int ssh_channel_waitwindow_termination(void *c){ - ssh_channel channel = (ssh_channel) c; - if (channel->remote_window > 0 || - channel->session->session_state == SSH_SESSION_STATE_ERROR || - channel->state == SSH_CHANNEL_STATE_CLOSED) - return 1; - else - return 0; +static int ssh_channel_waitwindow_termination(void *c) { + ssh_channel channel = (ssh_channel) c; + if (channel->remote_window > 0 || + channel->session->session_state == SSH_SESSION_STATE_ERROR || + channel->state == SSH_CHANNEL_STATE_CLOSED) + return 1; + else + return 0; } /* This termination function waits until the session is not in blocked status * anymore, e.g. because of a key re-exchange. */ -static int ssh_waitsession_unblocked(void *s){ +static int ssh_waitsession_unblocked(void *s) { ssh_session session = (ssh_session)s; - switch (session->session_state){ + switch (session->session_state) { case SSH_SESSION_STATE_DH: case SSH_SESSION_STATE_INITIAL_KEX: case SSH_SESSION_STATE_KEXINIT_RECEIVED: @@ -1305,151 +1306,152 @@ static int ssh_waitsession_unblocked(void *s){ * SSH_ERROR on error * SSH_AGAIN Timeout elapsed (or in nonblocking mode) */ -int ssh_channel_flush(ssh_channel channel){ - return ssh_blocking_flush(channel->session, SSH_TIMEOUT_DEFAULT); +int ssh_channel_flush(ssh_channel channel) { + return ssh_blocking_flush(channel->session, SSH_TIMEOUT_DEFAULT); } static int channel_write_common(ssh_channel channel, const void *data, uint32_t len, int is_stderr) { - ssh_session session; - uint32_t origlen = len; - size_t effectivelen; - size_t maxpacketlen; - int rc; - - if(channel == NULL) { - return -1; - } - session = channel->session; - if(data == NULL) { - ssh_set_error_invalid(session); - return -1; - } - - if (len > INT_MAX) { - SSH_LOG(SSH_LOG_PROTOCOL, - "Length (%u) is bigger than INT_MAX", len); - return SSH_ERROR; - } - - /* - * Handle the max packet len from remote side, be nice - * 10 bytes for the headers - */ - maxpacketlen = channel->remote_maxpacket - 10; - - if (channel->local_eof) { - ssh_set_error(session, SSH_REQUEST_DENIED, - "Can't write to channel %d:%d after EOF was sent", - channel->local_channel, - channel->remote_channel); - return -1; - } + ssh_session session; + uint32_t origlen = len; + size_t effectivelen; + size_t maxpacketlen; + int rc; - if (channel->state != SSH_CHANNEL_STATE_OPEN || channel->delayed_close != 0) { - ssh_set_error(session, SSH_REQUEST_DENIED, "Remote channel is closed"); + if (channel == NULL) { + return -1; + } + session = channel->session; + if (data == NULL) { + ssh_set_error_invalid(session); + return -1; + } - return -1; - } + if (len > INT_MAX) { + SSH_LOG(SSH_LOG_PROTOCOL, + "Length (%u) is bigger than INT_MAX", len); + return SSH_ERROR; + } - if (session->session_state == SSH_SESSION_STATE_ERROR) { - return SSH_ERROR; - } - - if (ssh_waitsession_unblocked(session) == 0){ - rc = ssh_handle_packets_termination(session, SSH_TIMEOUT_DEFAULT, - ssh_waitsession_unblocked, session); - if (rc == SSH_ERROR || !ssh_waitsession_unblocked(session)) - goto out; - } - while (len > 0) { - if (channel->remote_window < len) { - SSH_LOG(SSH_LOG_PROTOCOL, - "Remote window is %d bytes. going to write %d bytes", - channel->remote_window, - len); - /* What happens when the channel window is zero? */ - if(channel->remote_window == 0) { - /* nothing can be written */ - SSH_LOG(SSH_LOG_PROTOCOL, - "Wait for a growing window message..."); - rc = ssh_handle_packets_termination(session, SSH_TIMEOUT_DEFAULT, - ssh_channel_waitwindow_termination,channel); - if (rc == SSH_ERROR || - !ssh_channel_waitwindow_termination(channel) || - session->session_state == SSH_SESSION_STATE_ERROR || - channel->state == SSH_CHANNEL_STATE_CLOSED) - goto out; - continue; - } - effectivelen = MIN(len, channel->remote_window); - } else { - effectivelen = len; + /* + * Handle the max packet len from remote side, be nice + * 10 bytes for the headers + */ + maxpacketlen = channel->remote_maxpacket - 10; + + if (channel->local_eof) { + ssh_set_error(session, SSH_REQUEST_DENIED, + "Can't write to channel %d:%d after EOF was sent", + channel->local_channel, + channel->remote_channel); + return -1; } - effectivelen = MIN(effectivelen, maxpacketlen);; + if (channel->state != SSH_CHANNEL_STATE_OPEN || channel->delayed_close != 0) { + ssh_set_error(session, SSH_REQUEST_DENIED, "Remote channel is closed"); - rc = ssh_buffer_pack(session->out_buffer, - "bd", - is_stderr ? SSH2_MSG_CHANNEL_EXTENDED_DATA : SSH2_MSG_CHANNEL_DATA, - channel->remote_channel); - if (rc != SSH_OK) { - ssh_set_error_oom(session); - goto error; + return -1; } - /* stderr message has an extra field */ - if (is_stderr) { + if (session->session_state == SSH_SESSION_STATE_ERROR) { + return SSH_ERROR; + } + + if (ssh_waitsession_unblocked(session) == 0) { + rc = ssh_handle_packets_termination(session, SSH_TIMEOUT_DEFAULT, + ssh_waitsession_unblocked, session); + if (rc == SSH_ERROR || !ssh_waitsession_unblocked(session)) + goto out; + } + while (len > 0) { + if (channel->remote_window < len) { + SSH_LOG(SSH_LOG_PROTOCOL, + "Remote window is %d bytes. going to write %d bytes", + channel->remote_window, + len); + /* What happens when the channel window is zero? */ + if (channel->remote_window == 0) { + /* nothing can be written */ + SSH_LOG(SSH_LOG_PROTOCOL, + "Wait for a growing window message..."); + rc = ssh_handle_packets_termination(session, SSH_TIMEOUT_DEFAULT, + ssh_channel_waitwindow_termination, channel); + if (rc == SSH_ERROR || + !ssh_channel_waitwindow_termination(channel) || + session->session_state == SSH_SESSION_STATE_ERROR || + channel->state == SSH_CHANNEL_STATE_CLOSED) + goto out; + continue; + } + effectivelen = MIN(len, channel->remote_window); + } else { + effectivelen = len; + } + + effectivelen = MIN(effectivelen, maxpacketlen); + ; + rc = ssh_buffer_pack(session->out_buffer, - "d", - SSH2_EXTENDED_DATA_STDERR); + "bd", + is_stderr ? SSH2_MSG_CHANNEL_EXTENDED_DATA : SSH2_MSG_CHANNEL_DATA, + channel->remote_channel); if (rc != SSH_OK) { ssh_set_error_oom(session); goto error; } - } - /* append payload data */ - rc = ssh_buffer_pack(session->out_buffer, - "dP", - effectivelen, - (size_t)effectivelen, data); - if (rc != SSH_OK) { - ssh_set_error_oom(session); - goto error; - } + /* stderr message has an extra field */ + if (is_stderr) { + rc = ssh_buffer_pack(session->out_buffer, + "d", + SSH2_EXTENDED_DATA_STDERR); + if (rc != SSH_OK) { + ssh_set_error_oom(session); + goto error; + } + } - rc = ssh_packet_send(session); - if (rc == SSH_ERROR) { - return SSH_ERROR; - } + /* append payload data */ + rc = ssh_buffer_pack(session->out_buffer, + "dP", + effectivelen, + (size_t )effectivelen, data); + if (rc != SSH_OK) { + ssh_set_error_oom(session); + goto error; + } - SSH_LOG(SSH_LOG_PACKET, - "channel_write wrote %ld bytes", (long int) effectivelen); + rc = ssh_packet_send(session); + if (rc == SSH_ERROR) { + return SSH_ERROR; + } - channel->remote_window -= effectivelen; - len -= effectivelen; - data = ((uint8_t*)data + effectivelen); - if (channel->counter != NULL) { - channel->counter->out_bytes += effectivelen; + SSH_LOG(SSH_LOG_PACKET, + "channel_write wrote %ld bytes", (long int ) effectivelen); + + channel->remote_window -= effectivelen; + len -= effectivelen; + data = ((uint8_t*)data + effectivelen); + if (channel->counter != NULL) { + channel->counter->out_bytes += effectivelen; + } } - } - /* it's a good idea to flush the socket now */ - rc = ssh_channel_flush(channel); - if (rc == SSH_ERROR) { - goto error; - } + /* it's a good idea to flush the socket now */ + rc = ssh_channel_flush(channel); + if (rc == SSH_ERROR) { + goto error; + } out: - return (int)(origlen - len); + return (int)(origlen - len); error: - ssh_buffer_reinit(session->out_buffer); + ssh_buffer_reinit(session->out_buffer); - return SSH_ERROR; + return SSH_ERROR; } /** @@ -1487,7 +1489,7 @@ uint32_t ssh_channel_window_size(ssh_channel channel) { * @see ssh_channel_read() */ int ssh_channel_write(ssh_channel channel, const void *data, uint32_t len) { - return channel_write_common(channel, data, len, 0); + return channel_write_common(channel, data, len, 0); } /** @@ -1530,17 +1532,17 @@ int ssh_channel_is_closed(ssh_channel channel) { * @return 0 if there is no EOF, nonzero otherwise. */ int ssh_channel_is_eof(ssh_channel channel) { - if(channel == NULL) { - return SSH_ERROR; - } - if ((channel->stdout_buffer && - ssh_buffer_get_len(channel->stdout_buffer) > 0) || - (channel->stderr_buffer && - ssh_buffer_get_len(channel->stderr_buffer) > 0)) { - return 0; - } + if (channel == NULL) { + return SSH_ERROR; + } + if ((channel->stdout_buffer && + ssh_buffer_get_len(channel->stdout_buffer) > 0) || + (channel->stderr_buffer && + ssh_buffer_get_len(channel->stderr_buffer) > 0)) { + return 0; + } - return (channel->remote_eof != 0); + return (channel->remote_eof != 0); } /** @@ -1555,10 +1557,10 @@ int ssh_channel_is_eof(ssh_channel channel) { * @see ssh_set_blocking() */ void ssh_channel_set_blocking(ssh_channel channel, int blocking) { - if(channel == NULL) { - return; - } - ssh_set_blocking(channel->session,blocking); + if (channel == NULL) { + return; + } + ssh_set_blocking(channel->session, blocking); } /** @@ -1566,29 +1568,29 @@ void ssh_channel_set_blocking(ssh_channel channel, int blocking) { * * @brief handle a SSH_CHANNEL_SUCCESS packet and set the channel state. */ -SSH_PACKET_CALLBACK(ssh_packet_channel_success){ - ssh_channel channel; - (void)type; - (void)user; - - channel=channel_from_msg(session,packet); - if (channel == NULL) { - SSH_LOG(SSH_LOG_FUNCTIONS, "%s", ssh_get_error(session)); - return SSH_PACKET_USED; - } +SSH_PACKET_CALLBACK(ssh_packet_channel_success) { + ssh_channel channel; + (void)type; + (void)user; - SSH_LOG(SSH_LOG_PACKET, - "Received SSH_CHANNEL_SUCCESS on channel (%d:%d)", - channel->local_channel, - channel->remote_channel); - if(channel->request_state != SSH_CHANNEL_REQ_STATE_PENDING){ - SSH_LOG(SSH_LOG_RARE, "SSH_CHANNEL_SUCCESS received in incorrect state %d", - channel->request_state); - } else { - channel->request_state=SSH_CHANNEL_REQ_STATE_ACCEPTED; - } + channel = channel_from_msg(session, packet); + if (channel == NULL) { + SSH_LOG(SSH_LOG_FUNCTIONS, "%s", ssh_get_error(session)); + return SSH_PACKET_USED; + } + + SSH_LOG(SSH_LOG_PACKET, + "Received SSH_CHANNEL_SUCCESS on channel (%d:%d)", + channel->local_channel, + channel->remote_channel); + if (channel->request_state != SSH_CHANNEL_REQ_STATE_PENDING) { + SSH_LOG(SSH_LOG_RARE, "SSH_CHANNEL_SUCCESS received in incorrect state %d", + channel->request_state); + } else { + channel->request_state = SSH_CHANNEL_REQ_STATE_ACCEPTED; + } - return SSH_PACKET_USED; + return SSH_PACKET_USED; } /** @@ -1596,123 +1598,123 @@ SSH_PACKET_CALLBACK(ssh_packet_channel_success){ * * @brief Handle a SSH_CHANNEL_FAILURE packet and set the channel state. */ -SSH_PACKET_CALLBACK(ssh_packet_channel_failure){ - ssh_channel channel; - (void)type; - (void)user; +SSH_PACKET_CALLBACK(ssh_packet_channel_failure) { + ssh_channel channel; + (void)type; + (void)user; - channel=channel_from_msg(session,packet); - if (channel == NULL) { - SSH_LOG(SSH_LOG_FUNCTIONS, "%s", ssh_get_error(session)); + channel = channel_from_msg(session, packet); + if (channel == NULL) { + SSH_LOG(SSH_LOG_FUNCTIONS, "%s", ssh_get_error(session)); + + return SSH_PACKET_USED; + } + + SSH_LOG(SSH_LOG_PACKET, + "Received SSH_CHANNEL_FAILURE on channel (%d:%d)", + channel->local_channel, + channel->remote_channel); + if (channel->request_state != SSH_CHANNEL_REQ_STATE_PENDING) { + SSH_LOG(SSH_LOG_RARE, "SSH_CHANNEL_FAILURE received in incorrect state %d", + channel->request_state); + } else { + channel->request_state = SSH_CHANNEL_REQ_STATE_DENIED; + } return SSH_PACKET_USED; - } - - SSH_LOG(SSH_LOG_PACKET, - "Received SSH_CHANNEL_FAILURE on channel (%d:%d)", - channel->local_channel, - channel->remote_channel); - if(channel->request_state != SSH_CHANNEL_REQ_STATE_PENDING){ - SSH_LOG(SSH_LOG_RARE, "SSH_CHANNEL_FAILURE received in incorrect state %d", - channel->request_state); - } else { - channel->request_state=SSH_CHANNEL_REQ_STATE_DENIED; - } - - return SSH_PACKET_USED; -} - -static int ssh_channel_request_termination(void *c){ - ssh_channel channel = (ssh_channel)c; - if(channel->request_state != SSH_CHANNEL_REQ_STATE_PENDING || - channel->session->session_state == SSH_SESSION_STATE_ERROR) - return 1; - else - return 0; +} + +static int ssh_channel_request_termination(void *c) { + ssh_channel channel = (ssh_channel)c; + if (channel->request_state != SSH_CHANNEL_REQ_STATE_PENDING || + channel->session->session_state == SSH_SESSION_STATE_ERROR) + return 1; + else + return 0; } static int channel_request(ssh_channel channel, const char *request, - ssh_buffer buffer, int reply) { - ssh_session session = channel->session; - int rc = SSH_ERROR; - int ret; - - switch(channel->request_state){ - case SSH_CHANNEL_REQ_STATE_NONE: - break; - default: - goto pending; - } - - ret = ssh_buffer_pack(session->out_buffer, - "bdsb", - SSH2_MSG_CHANNEL_REQUEST, - channel->remote_channel, - request, - reply == 0 ? 0 : 1); - if (ret != SSH_OK) { - ssh_set_error_oom(session); - goto error; - } - - if (buffer != NULL) { - if (ssh_buffer_add_data(session->out_buffer, ssh_buffer_get(buffer), - ssh_buffer_get_len(buffer)) < 0) { - ssh_set_error_oom(session); - goto error; - } - } - channel->request_state = SSH_CHANNEL_REQ_STATE_PENDING; - if (ssh_packet_send(session) == SSH_ERROR) { - return rc; - } + ssh_buffer buffer, int reply) { + ssh_session session = channel->session; + int rc = SSH_ERROR; + int ret; - SSH_LOG(SSH_LOG_PACKET, - "Sent a SSH_MSG_CHANNEL_REQUEST %s", request); - if (reply == 0) { - channel->request_state = SSH_CHANNEL_REQ_STATE_NONE; - return SSH_OK; - } + switch (channel->request_state) { + case SSH_CHANNEL_REQ_STATE_NONE: + break; + default: + goto pending; + } + + ret = ssh_buffer_pack(session->out_buffer, + "bdsb", + SSH2_MSG_CHANNEL_REQUEST, + channel->remote_channel, + request, + reply == 0 ? 0 : 1); + if (ret != SSH_OK) { + ssh_set_error_oom(session); + goto error; + } + + if (buffer != NULL) { + if (ssh_buffer_add_data(session->out_buffer, ssh_buffer_get(buffer), + ssh_buffer_get_len(buffer)) < 0) { + ssh_set_error_oom(session); + goto error; + } + } + channel->request_state = SSH_CHANNEL_REQ_STATE_PENDING; + if (ssh_packet_send(session) == SSH_ERROR) { + return rc; + } + + SSH_LOG(SSH_LOG_PACKET, + "Sent a SSH_MSG_CHANNEL_REQUEST %s", request); + if (reply == 0) { + channel->request_state = SSH_CHANNEL_REQ_STATE_NONE; + return SSH_OK; + } pending: - rc = ssh_handle_packets_termination(session, - SSH_TIMEOUT_DEFAULT, - ssh_channel_request_termination, - channel); - - if(session->session_state == SSH_SESSION_STATE_ERROR || rc == SSH_ERROR) { - channel->request_state = SSH_CHANNEL_REQ_STATE_ERROR; - } - /* we received something */ - switch (channel->request_state){ - case SSH_CHANNEL_REQ_STATE_ERROR: - rc=SSH_ERROR; - break; - case SSH_CHANNEL_REQ_STATE_DENIED: - ssh_set_error(session, SSH_REQUEST_DENIED, - "Channel request %s failed", request); - rc=SSH_ERROR; - break; - case SSH_CHANNEL_REQ_STATE_ACCEPTED: - SSH_LOG(SSH_LOG_PROTOCOL, - "Channel request %s success",request); - rc=SSH_OK; - break; - case SSH_CHANNEL_REQ_STATE_PENDING: - rc = SSH_AGAIN; - return rc; - case SSH_CHANNEL_REQ_STATE_NONE: - /* Never reached */ - ssh_set_error(session, SSH_FATAL, "Invalid state in channel_request()"); - rc=SSH_ERROR; - break; - } - channel->request_state=SSH_CHANNEL_REQ_STATE_NONE; - - return rc; + rc = ssh_handle_packets_termination(session, + SSH_TIMEOUT_DEFAULT, + ssh_channel_request_termination, + channel); + + if (session->session_state == SSH_SESSION_STATE_ERROR || rc == SSH_ERROR) { + channel->request_state = SSH_CHANNEL_REQ_STATE_ERROR; + } + /* we received something */ + switch (channel->request_state) { + case SSH_CHANNEL_REQ_STATE_ERROR: + rc = SSH_ERROR; + break; + case SSH_CHANNEL_REQ_STATE_DENIED: + ssh_set_error(session, SSH_REQUEST_DENIED, + "Channel request %s failed", request); + rc = SSH_ERROR; + break; + case SSH_CHANNEL_REQ_STATE_ACCEPTED: + SSH_LOG(SSH_LOG_PROTOCOL, + "Channel request %s success", request); + rc = SSH_OK; + break; + case SSH_CHANNEL_REQ_STATE_PENDING: + rc = SSH_AGAIN; + return rc; + case SSH_CHANNEL_REQ_STATE_NONE: + /* Never reached */ + ssh_set_error(session, SSH_FATAL, "Invalid state in channel_request()"); + rc = SSH_ERROR; + break; + } + channel->request_state = SSH_CHANNEL_REQ_STATE_NONE; + + return rc; error: - ssh_buffer_reinit(session->out_buffer); + ssh_buffer_reinit(session->out_buffer); - return rc; + return rc; } /** @@ -1732,54 +1734,54 @@ error: * to be done again. */ int ssh_channel_request_pty_size(ssh_channel channel, const char *terminal, - int col, int row) { - ssh_session session; - ssh_buffer buffer = NULL; - int rc = SSH_ERROR; - - if(channel == NULL) { - return SSH_ERROR; - } - session = channel->session; - - if(terminal == NULL) { - ssh_set_error_invalid(channel->session); - return rc; - } - - switch(channel->request_state){ - case SSH_CHANNEL_REQ_STATE_NONE: - break; - default: - goto pending; - } - - buffer = ssh_buffer_new(); - if (buffer == NULL) { - ssh_set_error_oom(session); - goto error; - } - - rc = ssh_buffer_pack(buffer, - "sdddddb", - terminal, - col, - row, - 0, /* pix */ - 0, /* pix */ - 1, /* add a 0byte string */ - 0); - - if (rc != SSH_OK) { - ssh_set_error_oom(session); - goto error; - } + int col, int row) { + ssh_session session; + ssh_buffer buffer = NULL; + int rc = SSH_ERROR; + + if (channel == NULL) { + return SSH_ERROR; + } + session = channel->session; + + if (terminal == NULL) { + ssh_set_error_invalid(channel->session); + return rc; + } + + switch (channel->request_state) { + case SSH_CHANNEL_REQ_STATE_NONE: + break; + default: + goto pending; + } + + buffer = ssh_buffer_new(); + if (buffer == NULL) { + ssh_set_error_oom(session); + goto error; + } + + rc = ssh_buffer_pack(buffer, + "sdddddb", + terminal, + col, + row, + 0, /* pix */ + 0, /* pix */ + 1, /* add a 0byte string */ + 0); + + if (rc != SSH_OK) { + ssh_set_error_oom(session); + goto error; + } pending: - rc = channel_request(channel, "pty-req", buffer, 1); + rc = channel_request(channel, "pty-req", buffer, 1); error: - ssh_buffer_free(buffer); + ssh_buffer_free(buffer); - return rc; + return rc; } /** @@ -1795,7 +1797,7 @@ error: * @see ssh_channel_request_pty_size() */ int ssh_channel_request_pty(ssh_channel channel) { - return ssh_channel_request_pty_size(channel, "xterm", 80, 24); + return ssh_channel_request_pty_size(channel, "xterm", 80, 24); } /** @@ -1814,32 +1816,32 @@ int ssh_channel_request_pty(ssh_channel channel) { * time (not 100% threadsafe). */ int ssh_channel_change_pty_size(ssh_channel channel, int cols, int rows) { - ssh_session session = channel->session; - ssh_buffer buffer = NULL; - int rc = SSH_ERROR; - - buffer = ssh_buffer_new(); - if (buffer == NULL) { - ssh_set_error_oom(session); - goto error; - } - - rc = ssh_buffer_pack(buffer, - "dddd", - cols, - rows, - 0, /* pix */ - 0 /* pix */); - if (rc != SSH_OK) { - ssh_set_error_oom(session); - goto error; - } - - rc = channel_request(channel, "window-change", buffer, 0); + ssh_session session = channel->session; + ssh_buffer buffer = NULL; + int rc = SSH_ERROR; + + buffer = ssh_buffer_new(); + if (buffer == NULL) { + ssh_set_error_oom(session); + goto error; + } + + rc = ssh_buffer_pack(buffer, + "dddd", + cols, + rows, + 0, /* pix */ + 0 /* pix */); + if (rc != SSH_OK) { + ssh_set_error_oom(session); + goto error; + } + + rc = channel_request(channel, "window-change", buffer, 0); error: - ssh_buffer_free(buffer); + ssh_buffer_free(buffer); - return rc; + return rc; } /** @@ -1875,40 +1877,40 @@ int ssh_channel_request_shell(ssh_channel channel) { * @warning You normally don't have to call it for sftp, see sftp_new(). */ int ssh_channel_request_subsystem(ssh_channel channel, const char *subsys) { - ssh_buffer buffer = NULL; - int rc = SSH_ERROR; - - if(channel == NULL) { - return SSH_ERROR; - } - if(subsys == NULL) { - ssh_set_error_invalid(channel->session); - return rc; - } - switch(channel->request_state){ - case SSH_CHANNEL_REQ_STATE_NONE: - break; - default: - goto pending; - } - - buffer = ssh_buffer_new(); - if (buffer == NULL) { - ssh_set_error_oom(channel->session); - goto error; - } - - rc = ssh_buffer_pack(buffer, "s", subsys); - if (rc != SSH_OK) { - ssh_set_error_oom(channel->session); - goto error; - } + ssh_buffer buffer = NULL; + int rc = SSH_ERROR; + + if (channel == NULL) { + return SSH_ERROR; + } + if (subsys == NULL) { + ssh_set_error_invalid(channel->session); + return rc; + } + switch (channel->request_state) { + case SSH_CHANNEL_REQ_STATE_NONE: + break; + default: + goto pending; + } + + buffer = ssh_buffer_new(); + if (buffer == NULL) { + ssh_set_error_oom(channel->session); + goto error; + } + + rc = ssh_buffer_pack(buffer, "s", subsys); + if (rc != SSH_OK) { + ssh_set_error_oom(channel->session); + goto error; + } pending: - rc = channel_request(channel, "subsystem", buffer, 1); + rc = channel_request(channel, "subsystem", buffer, 1); error: - ssh_buffer_free(buffer); + ssh_buffer_free(buffer); - return rc; + return rc; } int ssh_channel_request_sftp( ssh_channel channel){ @@ -1919,23 +1921,23 @@ int ssh_channel_request_sftp( ssh_channel channel){ } static char *generate_cookie(void) { - static const char *hex = "0123456789abcdef"; - char s[36]; - unsigned char rnd[16]; - int ok; - int i; - - ok = ssh_get_random(rnd, sizeof(rnd), 0); - if (!ok) { - return NULL; - } + static const char *hex = "0123456789abcdef"; + char s[36]; + unsigned char rnd[16]; + int ok; + int i; + + ok = ssh_get_random(rnd, sizeof(rnd), 0); + if (!ok) { + return NULL; + } - for (i = 0; i < 16; i++) { - s[i*2] = hex[rnd[i] & 0x0f]; - s[i*2+1] = hex[rnd[i] >> 4]; - } - s[32] = '\0'; - return strdup(s); + for (i = 0; i < 16; i++) { + s[i * 2] = hex[rnd[i] & 0x0f]; + s[i * 2 + 1] = hex[rnd[i] >> 4]; + } + s[32] = '\0'; + return strdup(s); } /** @@ -1964,109 +1966,109 @@ static char *generate_cookie(void) { * to be done again. */ int ssh_channel_request_x11(ssh_channel channel, int single_connection, const char *protocol, - const char *cookie, int screen_number) { - ssh_buffer buffer = NULL; - char *c = NULL; - int rc = SSH_ERROR; - - if(channel == NULL) { - return SSH_ERROR; - } - switch(channel->request_state){ - case SSH_CHANNEL_REQ_STATE_NONE: - break; - default: - goto pending; - } - - buffer = ssh_buffer_new(); - if (buffer == NULL) { - ssh_set_error_oom(channel->session); - goto error; - } - - if (cookie == NULL) { - c = generate_cookie(); - if (c == NULL) { - ssh_set_error_oom(channel->session); - goto error; - } - } - - rc = ssh_buffer_pack(buffer, - "bssd", - single_connection == 0 ? 0 : 1, - protocol ? protocol : "MIT-MAGIC-COOKIE-1", - cookie ? cookie : c, - screen_number); - if (c != NULL){ - SAFE_FREE(c); - } - if (rc != SSH_OK) { - ssh_set_error_oom(channel->session); - goto error; - } + const char *cookie, int screen_number) { + ssh_buffer buffer = NULL; + char *c = NULL; + int rc = SSH_ERROR; + + if (channel == NULL) { + return SSH_ERROR; + } + switch (channel->request_state) { + case SSH_CHANNEL_REQ_STATE_NONE: + break; + default: + goto pending; + } + + buffer = ssh_buffer_new(); + if (buffer == NULL) { + ssh_set_error_oom(channel->session); + goto error; + } + + if (cookie == NULL) { + c = generate_cookie(); + if (c == NULL) { + ssh_set_error_oom(channel->session); + goto error; + } + } + + rc = ssh_buffer_pack(buffer, + "bssd", + single_connection == 0 ? 0 : 1, + protocol ? protocol : "MIT-MAGIC-COOKIE-1", + cookie ? cookie : c, + screen_number); + if (c != NULL) { + SAFE_FREE(c); + } + if (rc != SSH_OK) { + ssh_set_error_oom(channel->session); + goto error; + } pending: - rc = channel_request(channel, "x11-req", buffer, 1); + rc = channel_request(channel, "x11-req", buffer, 1); error: - ssh_buffer_free(buffer); - return rc; + ssh_buffer_free(buffer); + return rc; } static ssh_channel ssh_channel_accept(ssh_session session, int channeltype, int timeout_ms, int *destination_port) { #ifndef _WIN32 - static const struct timespec ts = { - .tv_sec = 0, - .tv_nsec = 50000000 /* 50ms */ - }; + static const struct timespec ts = { + .tv_sec = 0, + .tv_nsec = 50000000 /* 50ms */ + }; #endif - ssh_message msg = NULL; - ssh_channel channel = NULL; - struct ssh_iterator *iterator; - int t; - - /* - * We sleep for 50 ms in ssh_handle_packets() and later sleep for - * 50 ms. So we need to decrement by 100 ms. - */ - for (t = timeout_ms; t >= 0; t -= 100) { - if (timeout_ms == 0) { - ssh_handle_packets(session, 0); - } else { - ssh_handle_packets(session, 50); - } - - if (session->ssh_message_list) { - iterator = ssh_list_get_iterator(session->ssh_message_list); - while (iterator) { - msg = (ssh_message)iterator->data; - if (ssh_message_type(msg) == SSH_REQUEST_CHANNEL_OPEN && - ssh_message_subtype(msg) == channeltype) { - ssh_list_remove(session->ssh_message_list, iterator); - channel = ssh_message_channel_request_open_reply_accept(msg); - if(destination_port) { - *destination_port=msg->channel_request_open.destination_port; - } - - ssh_message_free(msg); - return channel; + ssh_message msg = NULL; + ssh_channel channel = NULL; + struct ssh_iterator *iterator; + int t; + + /* + * We sleep for 50 ms in ssh_handle_packets() and later sleep for + * 50 ms. So we need to decrement by 100 ms. + */ + for (t = timeout_ms; t >= 0; t -= 100) { + if (timeout_ms == 0) { + ssh_handle_packets(session, 0); + } else { + ssh_handle_packets(session, 50); } - iterator = iterator->next; - } - } - if(t>0){ + + if (session->ssh_message_list) { + iterator = ssh_list_get_iterator(session->ssh_message_list); + while (iterator) { + msg = (ssh_message)iterator->data; + if (ssh_message_type(msg) == SSH_REQUEST_CHANNEL_OPEN && + ssh_message_subtype(msg) == channeltype) { + ssh_list_remove(session->ssh_message_list, iterator); + channel = ssh_message_channel_request_open_reply_accept(msg); + if (destination_port) { + *destination_port = msg->channel_request_open.destination_port; + } + + ssh_message_free(msg); + return channel; + } + iterator = iterator->next; + } + } + if (t > 0) { #ifdef _WIN32 - Sleep(50); /* 50ms */ + Sleep(50); /* 50ms */ #else - nanosleep(&ts, NULL); + nanosleep(&ts, NULL); #endif + } } - } - ssh_set_error(session, SSH_NO_ERROR, "No channel request of this type from server"); - return NULL; + ssh_set_error(session, SSH_NO_ERROR, "No channel request of this type from server"); + return NULL; } /** @@ -2080,7 +2082,7 @@ static ssh_channel ssh_channel_accept(ssh_session session, int channeltype, * the server. */ ssh_channel ssh_channel_accept_x11(ssh_channel channel, int timeout_ms) { - return ssh_channel_accept(channel->session, SSH_CHANNEL_X11, timeout_ms, NULL); + return ssh_channel_accept(channel->session, SSH_CHANNEL_X11, timeout_ms, NULL); } /** @@ -2095,11 +2097,11 @@ ssh_channel ssh_channel_accept_x11(ssh_channel channel, int timeout_ms) { * @return SSH_OK on success, SSH_ERROR if an error occurred */ int ssh_channel_request_auth_agent(ssh_channel channel) { - if (channel == NULL) { - return SSH_ERROR; - } + if (channel == NULL) { + return SSH_ERROR; + } - return channel_request(channel, "auth-agent-req@xxxxxxxxxxx", NULL, 0); + return channel_request(channel, "auth-agent-req@xxxxxxxxxxx", NULL, 0); } /** @@ -2109,20 +2111,19 @@ int ssh_channel_request_auth_agent(ssh_channel channel) { * request. */ SSH_PACKET_CALLBACK(ssh_request_success){ - (void)type; - (void)user; - (void)packet; + (void)type; + (void)user; + (void)packet; - SSH_LOG(SSH_LOG_PACKET, - "Received SSH_REQUEST_SUCCESS"); - if(session->global_req_state != SSH_CHANNEL_REQ_STATE_PENDING){ - SSH_LOG(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; - } + SSH_LOG(SSH_LOG_PACKET, "Received SSH_REQUEST_SUCCESS"); + if (session->global_req_state != SSH_CHANNEL_REQ_STATE_PENDING) { + SSH_LOG(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; + } - return SSH_PACKET_USED; + return SSH_PACKET_USED; } /** @@ -2131,21 +2132,21 @@ SSH_PACKET_CALLBACK(ssh_request_success){ * @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; +SSH_PACKET_CALLBACK(ssh_request_denied) { + (void)type; + (void)user; + (void)packet; - SSH_LOG(SSH_LOG_PACKET, - "Received SSH_REQUEST_FAILURE"); - if(session->global_req_state != SSH_CHANNEL_REQ_STATE_PENDING){ - SSH_LOG(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; - } + SSH_LOG(SSH_LOG_PACKET, + "Received SSH_REQUEST_FAILURE"); + if (session->global_req_state != SSH_CHANNEL_REQ_STATE_PENDING) { + SSH_LOG(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; + } - return SSH_PACKET_USED; + return SSH_PACKET_USED; } @@ -2182,86 +2183,86 @@ int ssh_global_request(ssh_session session, ssh_buffer buffer, int reply) { - int rc; - - switch (session->global_req_state) { - case SSH_CHANNEL_REQ_STATE_NONE: - break; - default: - goto pending; - } - - rc = ssh_buffer_pack(session->out_buffer, - "bsb", - SSH2_MSG_GLOBAL_REQUEST, - request, - reply == 0 ? 0 : 1); - if (rc != SSH_OK){ - ssh_set_error_oom(session); - rc = SSH_ERROR; - goto error; - } - - if (buffer != NULL) { - rc = ssh_buffer_add_data(session->out_buffer, - ssh_buffer_get(buffer), - ssh_buffer_get_len(buffer)); - if (rc < 0) { - ssh_set_error_oom(session); - rc = SSH_ERROR; - goto error; - } - } - - session->global_req_state = SSH_CHANNEL_REQ_STATE_PENDING; - rc = ssh_packet_send(session); - if (rc == SSH_ERROR) { - return rc; - } - - SSH_LOG(SSH_LOG_PACKET, - "Sent a SSH_MSG_GLOBAL_REQUEST %s", request); - - if (reply == 0) { - session->global_req_state = SSH_CHANNEL_REQ_STATE_NONE; - - return SSH_OK; - } + int rc; + + switch (session->global_req_state) { + case SSH_CHANNEL_REQ_STATE_NONE: + break; + default: + goto pending; + } + + rc = ssh_buffer_pack(session->out_buffer, + "bsb", + SSH2_MSG_GLOBAL_REQUEST, + request, + reply == 0 ? 0 : 1); + if (rc != SSH_OK) { + ssh_set_error_oom(session); + rc = SSH_ERROR; + goto error; + } + + if (buffer != NULL) { + rc = ssh_buffer_add_data(session->out_buffer, + ssh_buffer_get(buffer), + ssh_buffer_get_len(buffer)); + if (rc < 0) { + ssh_set_error_oom(session); + rc = SSH_ERROR; + goto error; + } + } + + session->global_req_state = SSH_CHANNEL_REQ_STATE_PENDING; + rc = ssh_packet_send(session); + if (rc == SSH_ERROR) { + return rc; + } + + SSH_LOG(SSH_LOG_PACKET, + "Sent a SSH_MSG_GLOBAL_REQUEST %s", request); + + if (reply == 0) { + session->global_req_state = SSH_CHANNEL_REQ_STATE_NONE; + + return SSH_OK; + } pending: - rc = ssh_handle_packets_termination(session, - SSH_TIMEOUT_DEFAULT, - ssh_global_request_termination, - session); - - if(rc==SSH_ERROR || session->session_state == SSH_SESSION_STATE_ERROR){ - session->global_req_state = SSH_CHANNEL_REQ_STATE_ERROR; - } - switch(session->global_req_state){ - case SSH_CHANNEL_REQ_STATE_ACCEPTED: - SSH_LOG(SSH_LOG_PROTOCOL, "Global request %s success",request); - rc=SSH_OK; - break; - case SSH_CHANNEL_REQ_STATE_DENIED: - SSH_LOG(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: - rc = SSH_ERROR; - break; - case SSH_CHANNEL_REQ_STATE_PENDING: - return SSH_AGAIN; - } - session->global_req_state = SSH_CHANNEL_REQ_STATE_NONE; - - return rc; + rc = ssh_handle_packets_termination(session, + SSH_TIMEOUT_DEFAULT, + ssh_global_request_termination, + session); + + if (rc == SSH_ERROR || session->session_state == SSH_SESSION_STATE_ERROR) { + session->global_req_state = SSH_CHANNEL_REQ_STATE_ERROR; + } + switch (session->global_req_state) { + case SSH_CHANNEL_REQ_STATE_ACCEPTED: + SSH_LOG(SSH_LOG_PROTOCOL, "Global request %s success", request); + rc = SSH_OK; + break; + case SSH_CHANNEL_REQ_STATE_DENIED: + SSH_LOG(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: + rc = SSH_ERROR; + break; + case SSH_CHANNEL_REQ_STATE_PENDING: + return SSH_AGAIN; + } + session->global_req_state = SSH_CHANNEL_REQ_STATE_NONE; + + return rc; error: - ssh_buffer_reinit(session->out_buffer); + ssh_buffer_reinit(session->out_buffer); - return rc; + return rc; } /** @@ -2291,50 +2292,50 @@ int ssh_channel_listen_forward(ssh_session session, int port, int *bound_port) { - ssh_buffer buffer = NULL; - int rc = SSH_ERROR; - - if(session->global_req_state != SSH_CHANNEL_REQ_STATE_NONE) - goto pending; - - buffer = ssh_buffer_new(); - if (buffer == NULL) { - ssh_set_error_oom(session); - goto error; - } - - rc = ssh_buffer_pack(buffer, - "sd", - address ? address : "", - port); - if (rc != SSH_OK){ - ssh_set_error_oom(session); - goto error; - } + ssh_buffer buffer = NULL; + int rc = SSH_ERROR; + + if (session->global_req_state != SSH_CHANNEL_REQ_STATE_NONE) + goto pending; + + buffer = ssh_buffer_new(); + if (buffer == NULL) { + ssh_set_error_oom(session); + goto error; + } + + rc = ssh_buffer_pack(buffer, + "sd", + address ? address : "", + port); + if (rc != SSH_OK) { + ssh_set_error_oom(session); + goto error; + } pending: - rc = ssh_global_request(session, "tcpip-forward", buffer, 1); + rc = ssh_global_request(session, "tcpip-forward", buffer, 1); - /* TODO: FIXME no guarantee the last packet we received contains - * that info */ - if (rc == SSH_OK && port == 0 && bound_port != NULL) { - rc = ssh_buffer_unpack(session->in_buffer, "d", bound_port); - if (rc != SSH_OK) - *bound_port = 0; - } + /* TODO: FIXME no guarantee the last packet we received contains + * that info */ + if (rc == SSH_OK && port == 0 && bound_port != NULL) { + rc = ssh_buffer_unpack(session->in_buffer, "d", bound_port); + if (rc != SSH_OK) + *bound_port = 0; + } error: - ssh_buffer_free(buffer); - return rc; + ssh_buffer_free(buffer); + return rc; } /* DEPRECATED */ int ssh_forward_listen(ssh_session session, const char *address, int port, int *bound_port) { - return ssh_channel_listen_forward(session, address, port, bound_port); + return ssh_channel_listen_forward(session, address, port, bound_port); } /* DEPRECATED */ ssh_channel ssh_forward_accept(ssh_session session, int timeout_ms) { - return ssh_channel_accept(session, SSH_CHANNEL_FORWARDED_TCPIP, timeout_ms, NULL); + return ssh_channel_accept(session, SSH_CHANNEL_FORWARDED_TCPIP, timeout_ms, NULL); } /** @@ -2350,7 +2351,7 @@ ssh_channel ssh_forward_accept(ssh_session session, int timeout_ms) { * the server */ ssh_channel ssh_channel_accept_forward(ssh_session session, int timeout_ms, int* destination_port) { - return ssh_channel_accept(session, SSH_CHANNEL_FORWARDED_TCPIP, timeout_ms, destination_port); + return ssh_channel_accept(session, SSH_CHANNEL_FORWARDED_TCPIP, timeout_ms, destination_port); } /** @@ -2372,31 +2373,31 @@ int ssh_channel_cancel_forward(ssh_session session, const char *address, int port) { - ssh_buffer buffer = NULL; - int rc = SSH_ERROR; - - if(session->global_req_state != SSH_CHANNEL_REQ_STATE_NONE) - goto pending; - - buffer = ssh_buffer_new(); - if (buffer == NULL) { - ssh_set_error_oom(session); - goto error; - } - - rc = ssh_buffer_pack(buffer, "sd", - address ? address : "", - port); - if (rc != SSH_OK){ - ssh_set_error_oom(session); - goto error; - } + ssh_buffer buffer = NULL; + int rc = SSH_ERROR; + + if (session->global_req_state != SSH_CHANNEL_REQ_STATE_NONE) + goto pending; + + buffer = ssh_buffer_new(); + if (buffer == NULL) { + ssh_set_error_oom(session); + goto error; + } + + rc = ssh_buffer_pack(buffer, "sd", + address ? address : "", + port); + if (rc != SSH_OK) { + ssh_set_error_oom(session); + goto error; + } pending: - rc = ssh_global_request(session, "cancel-tcpip-forward", buffer, 1); + rc = ssh_global_request(session, "cancel-tcpip-forward", buffer, 1); error: - ssh_buffer_free(buffer); - return rc; + ssh_buffer_free(buffer); + return rc; } /* DEPRECATED */ @@ -2420,42 +2421,42 @@ int ssh_forward_cancel(ssh_session session, const char *address, int port) { * @warning Some environment variables may be refused by security reasons. */ int ssh_channel_request_env(ssh_channel channel, const char *name, const char *value) { - ssh_buffer buffer = NULL; - int rc = SSH_ERROR; - - if(channel == NULL) { - return SSH_ERROR; - } - if(name == NULL || value == NULL) { - ssh_set_error_invalid(channel->session); - return rc; - } - switch(channel->request_state){ - case SSH_CHANNEL_REQ_STATE_NONE: - break; - default: - goto pending; - } - buffer = ssh_buffer_new(); - if (buffer == NULL) { - ssh_set_error_oom(channel->session); - goto error; - } - - rc = ssh_buffer_pack(buffer, - "ss", - name, - value); - if (rc != SSH_OK){ - ssh_set_error_oom(channel->session); - goto error; - } + ssh_buffer buffer = NULL; + int rc = SSH_ERROR; + + if (channel == NULL) { + return SSH_ERROR; + } + if (name == NULL || value == NULL) { + ssh_set_error_invalid(channel->session); + return rc; + } + switch (channel->request_state) { + case SSH_CHANNEL_REQ_STATE_NONE: + break; + default: + goto pending; + } + buffer = ssh_buffer_new(); + if (buffer == NULL) { + ssh_set_error_oom(channel->session); + goto error; + } + + rc = ssh_buffer_pack(buffer, + "ss", + name, + value); + if (rc != SSH_OK) { + ssh_set_error_oom(channel->session); + goto error; + } pending: - rc = channel_request(channel, "env", buffer,1); + rc = channel_request(channel, "env", buffer,1); error: - ssh_buffer_free(buffer); + ssh_buffer_free(buffer); - return rc; + return rc; } /** @@ -2490,40 +2491,40 @@ error: * @see ssh_channel_request_shell() */ int ssh_channel_request_exec(ssh_channel channel, const char *cmd) { - ssh_buffer buffer = NULL; - int rc = SSH_ERROR; - - if(channel == NULL) { - return SSH_ERROR; - } - if(cmd == NULL) { - ssh_set_error_invalid(channel->session); - return rc; - } - - switch(channel->request_state){ - case SSH_CHANNEL_REQ_STATE_NONE: - break; - default: - goto pending; - } - buffer = ssh_buffer_new(); - if (buffer == NULL) { - ssh_set_error_oom(channel->session); - goto error; - } - - rc = ssh_buffer_pack(buffer, "s", cmd); - - if (rc != SSH_OK) { - ssh_set_error_oom(channel->session); - goto error; - } + ssh_buffer buffer = NULL; + int rc = SSH_ERROR; + + if (channel == NULL) { + return SSH_ERROR; + } + if (cmd == NULL) { + ssh_set_error_invalid(channel->session); + return rc; + } + + switch (channel->request_state) { + case SSH_CHANNEL_REQ_STATE_NONE: + break; + default: + goto pending; + } + buffer = ssh_buffer_new(); + if (buffer == NULL) { + ssh_set_error_oom(channel->session); + goto error; + } + + rc = ssh_buffer_pack(buffer, "s", cmd); + + if (rc != SSH_OK) { + ssh_set_error_oom(channel->session); + goto error; + } pending: - rc = channel_request(channel, "exec", buffer, 1); + rc = channel_request(channel, "exec", buffer, 1); error: - ssh_buffer_free(buffer); - return rc; + ssh_buffer_free(buffer); + return rc; } @@ -2560,33 +2561,33 @@ error: * (including attempts to send signal via SSH-v1 session). */ int ssh_channel_request_send_signal(ssh_channel channel, const char *sig) { - ssh_buffer buffer = NULL; - int rc = SSH_ERROR; - - if(channel == NULL) { - return SSH_ERROR; - } - if(sig == NULL) { - ssh_set_error_invalid(channel->session); - return rc; - } - - buffer = ssh_buffer_new(); - if (buffer == NULL) { - ssh_set_error_oom(channel->session); - goto error; - } - - rc = ssh_buffer_pack(buffer, "s", sig); - if (rc != SSH_OK) { - ssh_set_error_oom(channel->session); - goto error; - } - - rc = channel_request(channel, "signal", buffer, 0); + ssh_buffer buffer = NULL; + int rc = SSH_ERROR; + + if (channel == NULL) { + return SSH_ERROR; + } + if (sig == NULL) { + ssh_set_error_invalid(channel->session); + return rc; + } + + buffer = ssh_buffer_new(); + if (buffer == NULL) { + ssh_set_error_oom(channel->session); + goto error; + } + + rc = ssh_buffer_pack(buffer, "s", sig); + if (rc != SSH_OK) { + ssh_set_error_oom(channel->session); + goto error; + } + + rc = channel_request(channel, "signal", buffer, 0); error: - ssh_buffer_free(buffer); - return rc; + ssh_buffer_free(buffer); + return rc; } @@ -2654,79 +2655,79 @@ error: */ int channel_read_buffer(ssh_channel channel, ssh_buffer buffer, uint32_t count, int is_stderr) { - ssh_session session; - char buffer_tmp[8192]; - int r; - uint32_t total=0; - - if(channel == NULL) { - return SSH_ERROR; - } - session = channel->session; - - if(buffer == NULL) { - ssh_set_error_invalid(channel->session); - return SSH_ERROR; - } - - ssh_buffer_reinit(buffer); - if(count==0){ - do { - r=ssh_channel_poll(channel, is_stderr); - if(r < 0){ - return r; - } - if(r > 0){ - r=ssh_channel_read(channel, buffer_tmp, r, is_stderr); - if(r < 0){ - return r; - } - if(ssh_buffer_add_data(buffer,buffer_tmp,r) < 0){ - ssh_set_error_oom(session); - r = SSH_ERROR; - } + ssh_session session; + char buffer_tmp[8192]; + int r; + uint32_t total = 0; - return r; - } - if(ssh_channel_is_eof(channel)){ - return 0; - } - ssh_handle_packets(channel->session, SSH_TIMEOUT_INFINITE); - } while (r == 0); - } - while(total < count){ - r=ssh_channel_read(channel, buffer_tmp, sizeof(buffer_tmp), is_stderr); - if(r<0){ - return r; + if (channel == NULL) { + return SSH_ERROR; + } + session = channel->session; + + if (buffer == NULL) { + ssh_set_error_invalid(channel->session); + return SSH_ERROR; } - if(r==0){ - return total; + + ssh_buffer_reinit(buffer); + if (count == 0) { + do { + r = ssh_channel_poll(channel, is_stderr); + if (r < 0) { + return r; + } + if (r > 0) { + r = ssh_channel_read(channel, buffer_tmp, r, is_stderr); + if (r < 0) { + return r; + } + if (ssh_buffer_add_data(buffer, buffer_tmp, r) < 0) { + ssh_set_error_oom(session); + r = SSH_ERROR; + } + + return r; + } + if (ssh_channel_is_eof(channel)) { + return 0; + } + ssh_handle_packets(channel->session, SSH_TIMEOUT_INFINITE); + } while (r == 0); } - if (ssh_buffer_add_data(buffer,buffer_tmp,r) < 0) { - ssh_set_error_oom(session); + while (total < count) { + r = ssh_channel_read(channel, buffer_tmp, sizeof(buffer_tmp), is_stderr); + if (r < 0) { + return r; + } + if (r == 0) { + return total; + } + if (ssh_buffer_add_data(buffer, buffer_tmp, r) < 0) { + ssh_set_error_oom(session); - return SSH_ERROR; + return SSH_ERROR; + } + total += r; } - total += r; - } - return total; + return total; } struct ssh_channel_read_termination_struct { - ssh_channel channel; - uint32_t count; - ssh_buffer buffer; + ssh_channel channel; + uint32_t count; + ssh_buffer buffer; }; static int ssh_channel_read_termination(void *s){ - struct ssh_channel_read_termination_struct *ctx = s; - if (ssh_buffer_get_len(ctx->buffer) >= ctx->count || - ctx->channel->remote_eof || - ctx->channel->session->session_state == SSH_SESSION_STATE_ERROR) - return 1; - else - return 0; + struct ssh_channel_read_termination_struct *ctx = s; + if (ssh_buffer_get_len(ctx->buffer) >= ctx->count || + ctx->channel->remote_eof || + ctx->channel->session->session_state == SSH_SESSION_STATE_ERROR) + return 1; + else + return 0; } /* TODO FIXME Fix the delayed close thing */ @@ -2790,97 +2791,97 @@ int ssh_channel_read_timeout(ssh_channel channel, int is_stderr, int timeout_ms) { - ssh_session session; - ssh_buffer stdbuf; - uint32_t len; - struct ssh_channel_read_termination_struct ctx; - int rc; - - if(channel == NULL) { - return SSH_ERROR; - } - if(dest == NULL) { - ssh_set_error_invalid(channel->session); - return SSH_ERROR; - } - - session = channel->session; - stdbuf = channel->stdout_buffer; - - if (count == 0) { - return 0; - } - - if (is_stderr) { - stdbuf=channel->stderr_buffer; - } - - /* - * We may have problem if the window is too small to accept as much data - * as asked - */ - SSH_LOG(SSH_LOG_PACKET, - "Read (%d) buffered : %d bytes. Window: %d", - count, - ssh_buffer_get_len(stdbuf), - channel->local_window); - - if (count > ssh_buffer_get_len(stdbuf) + channel->local_window) { - if (grow_window(session, channel, count - ssh_buffer_get_len(stdbuf)) < 0) { - return -1; - } - } - - /* block reading until at least one byte has been read - * and ignore the trivial case count=0 - */ - ctx.channel = channel; - ctx.buffer = stdbuf; - ctx.count = 1; - - if (timeout_ms < SSH_TIMEOUT_DEFAULT) { - timeout_ms = SSH_TIMEOUT_INFINITE; - } - - rc = ssh_handle_packets_termination(session, - timeout_ms, - ssh_channel_read_termination, - &ctx); - if (rc == SSH_ERROR){ - return rc; - } - - /* - * If the channel is closed or in an error state, reading from it is an error - */ - if (session->session_state == SSH_SESSION_STATE_ERROR) { - return SSH_ERROR; - } - if (channel->state == SSH_CHANNEL_STATE_CLOSED) { - ssh_set_error(session, - SSH_FATAL, - "Remote channel is closed."); - return SSH_ERROR; - } - if (channel->remote_eof && ssh_buffer_get_len(stdbuf) == 0) { - return 0; - } - len = ssh_buffer_get_len(stdbuf); - /* Read count bytes if len is greater, everything otherwise */ - len = (len > count ? count : len); - memcpy(dest, ssh_buffer_get(stdbuf), len); - ssh_buffer_pass_bytes(stdbuf,len); - if (channel->counter != NULL) { - channel->counter->in_bytes += len; - } - /* Authorize some buffering while userapp is busy */ - if (channel->local_window < WINDOWLIMIT) { - if (grow_window(session, channel, 0) < 0) { - return -1; + ssh_session session; + ssh_buffer stdbuf; + uint32_t len; + struct ssh_channel_read_termination_struct ctx; + int rc; + + if (channel == NULL) { + return SSH_ERROR; + } + if (dest == NULL) { + ssh_set_error_invalid(channel->session); + return SSH_ERROR; + } + + session = channel->session; + stdbuf = channel->stdout_buffer; + + if (count == 0) { + return 0; + } + + if (is_stderr) { + stdbuf = channel->stderr_buffer; + } + + /* + * We may have problem if the window is too small to accept as much data + * as asked + */ + SSH_LOG(SSH_LOG_PACKET, + "Read (%d) buffered : %d bytes. Window: %d", + count, + ssh_buffer_get_len(stdbuf), + channel->local_window); + + if (count > ssh_buffer_get_len(stdbuf) + channel->local_window) { + if (grow_window(session, channel, count - ssh_buffer_get_len(stdbuf)) < 0) { + return -1; + } + } + + /* block reading until at least one byte has been read + * and ignore the trivial case count=0 + */ + ctx.channel = channel; + ctx.buffer = stdbuf; + ctx.count = 1; + + if (timeout_ms < SSH_TIMEOUT_DEFAULT) { + timeout_ms = SSH_TIMEOUT_INFINITE; + } + + rc = ssh_handle_packets_termination(session, + timeout_ms, + ssh_channel_read_termination, + &ctx); + if (rc == SSH_ERROR) { + return rc; + } + + /* + * If the channel is closed or in an error state, reading from it is an error + */ + if (session->session_state == SSH_SESSION_STATE_ERROR) { + return SSH_ERROR; + } + if (channel->state == SSH_CHANNEL_STATE_CLOSED) { + ssh_set_error(session, + SSH_FATAL, + "Remote channel is closed."); + return SSH_ERROR; + } + if (channel->remote_eof && ssh_buffer_get_len(stdbuf) == 0) { + return 0; + } + len = ssh_buffer_get_len(stdbuf); + /* Read count bytes if len is greater, everything otherwise */ + len = (len > count ? count : len); + memcpy(dest, ssh_buffer_get(stdbuf), len); + ssh_buffer_pass_bytes(stdbuf, len); + if (channel->counter != NULL) { + channel->counter->in_bytes += len; + } + /* Authorize some buffering while userapp is busy */ + if (channel->local_window < WINDOWLIMIT) { + if (grow_window(session, channel, 0) < 0) { + return -1; + } } - } - return len; + return len; } /** @@ -2906,40 +2907,40 @@ int ssh_channel_read_timeout(ssh_channel channel, */ int ssh_channel_read_nonblocking(ssh_channel channel, void *dest, uint32_t count, int is_stderr) { - ssh_session session; - int to_read; - int rc; - int blocking; + ssh_session session; + int to_read; + int rc; + int blocking; - if(channel == NULL) { - return SSH_ERROR; - } - if(dest == NULL) { - ssh_set_error_invalid(channel->session); - return SSH_ERROR; - } + if (channel == NULL) { + return SSH_ERROR; + } + if (dest == NULL) { + ssh_set_error_invalid(channel->session); + return SSH_ERROR; + } - session = channel->session; + session = channel->session; - to_read = ssh_channel_poll(channel, is_stderr); + to_read = ssh_channel_poll(channel, is_stderr); - if (to_read <= 0) { - if (session->session_state == SSH_SESSION_STATE_ERROR){ - return SSH_ERROR; - } + if (to_read <= 0) { + if (session->session_state == SSH_SESSION_STATE_ERROR) { + return SSH_ERROR; + } - return to_read; /* may be an error code */ - } + return to_read; /* may be an error code */ + } - if (to_read > (int)count) { - to_read = (int)count; - } - blocking = ssh_is_blocking(session); - ssh_set_blocking(session, 0); - rc = ssh_channel_read(channel, dest, to_read, is_stderr); - ssh_set_blocking(session,blocking); + if (to_read > (int)count) { + to_read = (int)count; + } + blocking = ssh_is_blocking(session); + ssh_set_blocking(session, 0); + rc = ssh_channel_read(channel, dest, to_read, is_stderr); + ssh_set_blocking(session, blocking); - return rc; + return rc; } /** @@ -2957,36 +2958,36 @@ int ssh_channel_read_nonblocking(ssh_channel channel, void *dest, uint32_t count * @see ssh_channel_is_eof() */ int ssh_channel_poll(ssh_channel channel, int is_stderr){ - ssh_buffer stdbuf; + ssh_buffer stdbuf; - if(channel == NULL) { - return SSH_ERROR; - } - - stdbuf = channel->stdout_buffer; + if (channel == NULL) { + return SSH_ERROR; + } - if (is_stderr) { - stdbuf = channel->stderr_buffer; - } + stdbuf = channel->stdout_buffer; - if (ssh_buffer_get_len(stdbuf) == 0 && channel->remote_eof == 0) { - if (channel->session->session_state == SSH_SESSION_STATE_ERROR){ - return SSH_ERROR; + if (is_stderr) { + stdbuf = channel->stderr_buffer; } - if (ssh_handle_packets(channel->session, SSH_TIMEOUT_NONBLOCKING)==SSH_ERROR) { - return SSH_ERROR; + + if (ssh_buffer_get_len(stdbuf) == 0 && channel->remote_eof == 0) { + if (channel->session->session_state == SSH_SESSION_STATE_ERROR) { + return SSH_ERROR; + } + if (ssh_handle_packets(channel->session, SSH_TIMEOUT_NONBLOCKING) == SSH_ERROR) { + return SSH_ERROR; + } } - } - if (ssh_buffer_get_len(stdbuf) > 0){ - return ssh_buffer_get_len(stdbuf); - } + if (ssh_buffer_get_len(stdbuf) > 0) { + return ssh_buffer_get_len(stdbuf); + } - if (channel->remote_eof) { - return SSH_EOF; - } + if (channel->remote_eof) { + return SSH_EOF; + } - return ssh_buffer_get_len(stdbuf); + return ssh_buffer_get_len(stdbuf); } /** @@ -3009,37 +3010,37 @@ int ssh_channel_poll(ssh_channel channel, int is_stderr){ * @see ssh_channel_is_eof() */ int ssh_channel_poll_timeout(ssh_channel channel, int timeout, int is_stderr){ - ssh_session session; - ssh_buffer stdbuf; - struct ssh_channel_read_termination_struct ctx; - int rc; - - if(channel == NULL) { - return SSH_ERROR; - } - - session = channel->session; - stdbuf = channel->stdout_buffer; - - if (is_stderr) { - stdbuf = channel->stderr_buffer; - } - ctx.buffer = stdbuf; - ctx.channel = channel; - ctx.count = 1; - rc = ssh_handle_packets_termination(channel->session, timeout, - ssh_channel_read_termination, &ctx); - if(rc ==SSH_ERROR || session->session_state == SSH_SESSION_STATE_ERROR){ - rc = SSH_ERROR; - goto end; - } - rc = ssh_buffer_get_len(stdbuf); - if(rc > 0) - goto end; - if (channel->remote_eof) - rc = SSH_EOF; + ssh_session session; + ssh_buffer stdbuf; + struct ssh_channel_read_termination_struct ctx; + int rc; + + if (channel == NULL) { + return SSH_ERROR; + } + + session = channel->session; + stdbuf = channel->stdout_buffer; + + if (is_stderr) { + stdbuf = channel->stderr_buffer; + } + ctx.buffer = stdbuf; + ctx.channel = channel; + ctx.count = 1; + rc = ssh_handle_packets_termination(channel->session, timeout, + ssh_channel_read_termination, &ctx); + if (rc == SSH_ERROR || session->session_state == SSH_SESSION_STATE_ERROR) { + rc = SSH_ERROR; + goto end; + } + rc = ssh_buffer_get_len(stdbuf); + if (rc > 0) + goto end; + if (channel->remote_eof) + rc = SSH_EOF; end: - return rc; + return rc; } /** @@ -3050,23 +3051,23 @@ end: * @return The session pointer. */ ssh_session ssh_channel_get_session(ssh_channel channel) { - if(channel == NULL) { - return NULL; - } + if (channel == NULL) { + return NULL; + } - return channel->session; + return channel->session; } static int ssh_channel_exit_status_termination(void *c){ - ssh_channel channel = c; - if(channel->exit_status != -1 || - /* When a channel is closed, no exit status message can - * come anymore */ - (channel->flags & SSH_CHANNEL_FLAG_CLOSED_REMOTE) || - channel->session->session_state == SSH_SESSION_STATE_ERROR) - return 1; - else - return 0; + ssh_channel channel = c; + if (channel->exit_status != -1 || + /* When a channel is closed, no exit status message can + * come anymore */ + (channel->flags & SSH_CHANNEL_FLAG_CLOSED_REMOTE) || + channel->session->session_state == SSH_SESSION_STATE_ERROR) + return 1; + else + return 0; } /** @@ -3086,18 +3087,18 @@ static int ssh_channel_exit_status_termination(void *c){ * @see ssh_channel_exit_status_callback */ int ssh_channel_get_exit_status(ssh_channel channel) { - int rc; - if(channel == NULL) { - return SSH_ERROR; - } - rc = ssh_handle_packets_termination(channel->session, - SSH_TIMEOUT_DEFAULT, - ssh_channel_exit_status_termination, - channel); - if (rc == SSH_ERROR || channel->session->session_state == - SSH_SESSION_STATE_ERROR) - return SSH_ERROR; - return channel->exit_status; + int rc; + if (channel == NULL) { + return SSH_ERROR; + } + rc = ssh_handle_packets_termination(channel->session, + SSH_TIMEOUT_DEFAULT, + ssh_channel_exit_status_termination, + channel); + if (rc == SSH_ERROR || channel->session->session_state == + SSH_SESSION_STATE_ERROR) + return SSH_ERROR; + return channel->exit_status; } /* @@ -3111,59 +3112,59 @@ int ssh_channel_get_exit_status(ssh_channel channel) { */ static int channel_protocol_select(ssh_channel *rchans, ssh_channel *wchans, ssh_channel *echans, ssh_channel *rout, ssh_channel *wout, ssh_channel *eout) { - ssh_channel chan; - int i; - int j = 0; + ssh_channel chan; + int i; + int j = 0; - for (i = 0; rchans[i] != NULL; i++) { - chan = rchans[i]; + for (i = 0; rchans[i] != NULL; i++) { + chan = rchans[i]; - while (ssh_channel_is_open(chan) && ssh_socket_data_available(chan->session->socket)) { - ssh_handle_packets(chan->session, SSH_TIMEOUT_NONBLOCKING); - } + while (ssh_channel_is_open(chan) && ssh_socket_data_available(chan->session->socket)) { + ssh_handle_packets(chan->session, SSH_TIMEOUT_NONBLOCKING); + } - if ((chan->stdout_buffer && ssh_buffer_get_len(chan->stdout_buffer) > 0) || - (chan->stderr_buffer && ssh_buffer_get_len(chan->stderr_buffer) > 0) || - chan->remote_eof) { - rout[j] = chan; - j++; + if ((chan->stdout_buffer && ssh_buffer_get_len(chan->stdout_buffer) > 0) || + (chan->stderr_buffer && ssh_buffer_get_len(chan->stderr_buffer) > 0) || + chan->remote_eof) { + rout[j] = chan; + j++; + } } - } - rout[j] = NULL; + rout[j] = NULL; - j = 0; - for(i = 0; wchans[i] != NULL; i++) { - chan = wchans[i]; - /* It's not our business to seek if the file descriptor is writable */ - if (ssh_socket_data_writable(chan->session->socket) && - ssh_channel_is_open(chan) && (chan->remote_window > 0)) { - wout[j] = chan; - j++; + j = 0; + for (i = 0; wchans[i] != NULL; i++) { + chan = wchans[i]; + /* It's not our business to seek if the file descriptor is writable */ + if (ssh_socket_data_writable(chan->session->socket) && + ssh_channel_is_open(chan) && (chan->remote_window > 0)) { + wout[j] = chan; + j++; + } } - } - wout[j] = NULL; + wout[j] = NULL; - j = 0; - for (i = 0; echans[i] != NULL; i++) { - chan = echans[i]; + j = 0; + for (i = 0; echans[i] != NULL; i++) { + chan = echans[i]; - if (!ssh_socket_is_open(chan->session->socket) || ssh_channel_is_closed(chan)) { - eout[j] = chan; - j++; + if (!ssh_socket_is_open(chan->session->socket) || ssh_channel_is_closed(chan)) { + eout[j] = chan; + j++; + } } - } - eout[j] = NULL; + eout[j] = NULL; - return 0; + return 0; } /* Just count number of pointers in the array */ static int count_ptrs(ssh_channel *ptrs) { - int c; - for (c = 0; ptrs[c] != NULL; c++) - ; + int c; + for (c = 0; ptrs[c] != NULL; c++) + ; - return c; + return c; } /** @@ -3190,118 +3191,118 @@ static int count_ptrs(ssh_channel *ptrs) { */ int ssh_channel_select(ssh_channel *readchans, ssh_channel *writechans, ssh_channel *exceptchans, struct timeval * timeout) { - ssh_channel *rchans, *wchans, *echans; - ssh_channel dummy = NULL; - ssh_event event = NULL; - int rc; - int i; - int tm, tm_base; - int firstround=1; - struct ssh_timestamp ts; - - if (timeout != NULL) - tm_base = timeout->tv_sec * 1000 + timeout->tv_usec/1000; - else - tm_base = SSH_TIMEOUT_INFINITE; - ssh_timestamp_init(&ts); - tm = tm_base; - /* don't allow NULL pointers */ - if (readchans == NULL) { - readchans = &dummy; - } - - if (writechans == NULL) { - writechans = &dummy; - } - - if (exceptchans == NULL) { - exceptchans = &dummy; - } - - if (readchans[0] == NULL && writechans[0] == NULL && exceptchans[0] == NULL) { - /* No channel to poll?? Go away! */ - return 0; - } + ssh_channel *rchans, *wchans, *echans; + ssh_channel dummy = NULL; + ssh_event event = NULL; + int rc; + int i; + int tm, tm_base; + int firstround = 1; + struct ssh_timestamp ts; - /* Prepare the outgoing temporary arrays */ - rchans = calloc(count_ptrs(readchans) + 1, sizeof(ssh_channel)); - if (rchans == NULL) { - return SSH_ERROR; - } + if (timeout != NULL) + tm_base = timeout->tv_sec * 1000 + timeout->tv_usec / 1000; + else + tm_base = SSH_TIMEOUT_INFINITE; + ssh_timestamp_init(&ts); + tm = tm_base; + /* don't allow NULL pointers */ + if (readchans == NULL) { + readchans = &dummy; + } - wchans = calloc(count_ptrs(writechans) + 1, sizeof(ssh_channel)); - if (wchans == NULL) { - SAFE_FREE(rchans); - return SSH_ERROR; - } + if (writechans == NULL) { + writechans = &dummy; + } + + if (exceptchans == NULL) { + exceptchans = &dummy; + } + + if (readchans[0] == NULL && writechans[0] == NULL && exceptchans[0] == NULL) { + /* No channel to poll?? Go away! */ + return 0; + } + + /* Prepare the outgoing temporary arrays */ + rchans = calloc(count_ptrs(readchans) + 1, sizeof(ssh_channel)); + if (rchans == NULL) { + return SSH_ERROR; + } + + wchans = calloc(count_ptrs(writechans) + 1, sizeof(ssh_channel)); + if (wchans == NULL) { + SAFE_FREE(rchans); + return SSH_ERROR; + } + + echans = calloc(count_ptrs(exceptchans) + 1, sizeof(ssh_channel)); + if (echans == NULL) { + SAFE_FREE(rchans); + SAFE_FREE(wchans); + return SSH_ERROR; + } + + /* + * First, try without doing network stuff then, use the ssh_poll + * infrastructure to poll on all sessions. + */ + do { + channel_protocol_select(readchans, writechans, exceptchans, + rchans, wchans, echans); + if (rchans[0] != NULL || wchans[0] != NULL || echans[0] != NULL) { + /* At least one channel has an event */ + break; + } + /* Add all channels' sessions right into an event object */ + if (event == NULL) { + event = ssh_event_new(); + if (event == NULL) { + SAFE_FREE(rchans); + SAFE_FREE(wchans); + SAFE_FREE(echans); + + return SSH_ERROR; + } + for (i = 0; readchans[i] != NULL; i++) { + ssh_poll_get_default_ctx(readchans[i]->session); + ssh_event_add_session(event, readchans[i]->session); + } + for (i = 0; writechans[i] != NULL; i++) { + ssh_poll_get_default_ctx(writechans[i]->session); + ssh_event_add_session(event, writechans[i]->session); + } + for (i = 0; exceptchans[i] != NULL; i++) { + ssh_poll_get_default_ctx(exceptchans[i]->session); + ssh_event_add_session(event, exceptchans[i]->session); + } + } + /* Get out if the timeout has elapsed */ + if (!firstround && ssh_timeout_elapsed(&ts, tm_base)) { + break; + } + /* Here we go */ + rc = ssh_event_dopoll(event, tm); + if (rc != SSH_OK) { + SAFE_FREE(rchans); + SAFE_FREE(wchans); + SAFE_FREE(echans); + ssh_event_free(event); + return rc; + } + tm = ssh_timeout_update(&ts, tm_base); + firstround = 0; + } while (1); - echans = calloc(count_ptrs(exceptchans) + 1, sizeof(ssh_channel)); - if (echans == NULL) { + memcpy(readchans, rchans, (count_ptrs(rchans) + 1) * sizeof(ssh_channel)); + memcpy(writechans, wchans, (count_ptrs(wchans) + 1) * sizeof(ssh_channel)); + memcpy(exceptchans, echans, (count_ptrs(echans) + 1) * sizeof(ssh_channel)); SAFE_FREE(rchans); SAFE_FREE(wchans); - return SSH_ERROR; - } - - /* - * First, try without doing network stuff then, use the ssh_poll - * infrastructure to poll on all sessions. - */ - do { - channel_protocol_select(readchans, writechans, exceptchans, - rchans, wchans, echans); - if (rchans[0] != NULL || wchans[0] != NULL || echans[0] != NULL) { - /* At least one channel has an event */ - break; - } - /* Add all channels' sessions right into an event object */ - if (event == NULL) { - event = ssh_event_new(); - if (event == NULL) { - SAFE_FREE(rchans); - SAFE_FREE(wchans); - SAFE_FREE(echans); - - return SSH_ERROR; - } - for (i = 0; readchans[i] != NULL; i++) { - ssh_poll_get_default_ctx(readchans[i]->session); - ssh_event_add_session(event, readchans[i]->session); - } - for (i = 0; writechans[i] != NULL; i++) { - ssh_poll_get_default_ctx(writechans[i]->session); - ssh_event_add_session(event, writechans[i]->session); - } - for (i = 0; exceptchans[i] != NULL; i++) { - ssh_poll_get_default_ctx(exceptchans[i]->session); - ssh_event_add_session(event, exceptchans[i]->session); - } - } - /* Get out if the timeout has elapsed */ - if (!firstround && ssh_timeout_elapsed(&ts, tm_base)){ - break; - } - /* Here we go */ - rc = ssh_event_dopoll(event,tm); - if (rc != SSH_OK){ - SAFE_FREE(rchans); - SAFE_FREE(wchans); - SAFE_FREE(echans); - ssh_event_free(event); - return rc; - } - tm = ssh_timeout_update(&ts, tm_base); - firstround=0; - } while(1); - - memcpy(readchans, rchans, (count_ptrs(rchans) + 1) * sizeof(ssh_channel )); - memcpy(writechans, wchans, (count_ptrs(wchans) + 1) * sizeof(ssh_channel )); - memcpy(exceptchans, echans, (count_ptrs(echans) + 1) * sizeof(ssh_channel )); - SAFE_FREE(rchans); - SAFE_FREE(wchans); - SAFE_FREE(echans); - if(event) - ssh_event_free(event); - return 0; + SAFE_FREE(echans); + if (event) + ssh_event_free(event); + return 0; } /** @@ -3343,7 +3344,7 @@ void ssh_channel_set_counter(ssh_channel channel, * @see ssh_channel_read() */ int ssh_channel_write_stderr(ssh_channel channel, const void *data, uint32_t len) { - return channel_write_common(channel, data, len, 1); + return channel_write_common(channel, data, len, 1); } #if WITH_SERVER @@ -3374,48 +3375,48 @@ int ssh_channel_write_stderr(ssh_channel channel, const void *data, uint32_t len */ int ssh_channel_open_reverse_forward(ssh_channel channel, const char *remotehost, int remoteport, const char *sourcehost, int localport) { - ssh_session session; - ssh_buffer payload = NULL; - int rc = SSH_ERROR; - - if(channel == NULL) { - return rc; - } - if(remotehost == NULL || sourcehost == NULL) { - ssh_set_error_invalid(channel->session); - return rc; - } - - session = channel->session; - - if(channel->state != SSH_CHANNEL_STATE_NOT_OPEN) - goto pending; - payload = ssh_buffer_new(); - if (payload == NULL) { - ssh_set_error_oom(session); - goto error; - } - rc = ssh_buffer_pack(payload, - "sdsd", - remotehost, - remoteport, - sourcehost, - localport); - if (rc != SSH_OK){ - ssh_set_error_oom(session); - goto error; - } + ssh_session session; + ssh_buffer payload = NULL; + int rc = SSH_ERROR; + + if (channel == NULL) { + return rc; + } + if (remotehost == NULL || sourcehost == NULL) { + ssh_set_error_invalid(channel->session); + return rc; + } + + session = channel->session; + + if (channel->state != SSH_CHANNEL_STATE_NOT_OPEN) + goto pending; + payload = ssh_buffer_new(); + if (payload == NULL) { + ssh_set_error_oom(session); + goto error; + } + rc = ssh_buffer_pack(payload, + "sdsd", + remotehost, + remoteport, + sourcehost, + localport); + if (rc != SSH_OK) { + ssh_set_error_oom(session); + goto error; + } pending: - rc = channel_open(channel, - "forwarded-tcpip", - CHANNEL_INITIAL_WINDOW, - CHANNEL_MAX_PACKET, - payload); + rc = channel_open(channel, + "forwarded-tcpip", + CHANNEL_INITIAL_WINDOW, + CHANNEL_MAX_PACKET, + payload); error: - ssh_buffer_free(payload); + ssh_buffer_free(payload); - return rc; + return rc; } /** @@ -3435,49 +3436,49 @@ error: * forward the content of a socket to the channel. You still have to * use channel_read and channel_write for this. */ -int ssh_channel_open_x11(ssh_channel channel, +int ssh_channel_open_x11(ssh_channel channel, const char *orig_addr, int orig_port) { - ssh_session session; - ssh_buffer payload = NULL; - int rc = SSH_ERROR; - - if(channel == NULL) { - return rc; - } - if(orig_addr == NULL) { - ssh_set_error_invalid(channel->session); - return rc; - } - session = channel->session; - - if(channel->state != SSH_CHANNEL_STATE_NOT_OPEN) - goto pending; - - payload = ssh_buffer_new(); - if (payload == NULL) { - ssh_set_error_oom(session); - goto error; - } - - rc = ssh_buffer_pack(payload, - "sd", - orig_addr, - orig_port); - if (rc != SSH_OK) { - ssh_set_error_oom(session); - goto error; - } + ssh_session session; + ssh_buffer payload = NULL; + int rc = SSH_ERROR; + + if (channel == NULL) { + return rc; + } + if (orig_addr == NULL) { + ssh_set_error_invalid(channel->session); + return rc; + } + session = channel->session; + + if (channel->state != SSH_CHANNEL_STATE_NOT_OPEN) + goto pending; + + payload = ssh_buffer_new(); + if (payload == NULL) { + ssh_set_error_oom(session); + goto error; + } + + rc = ssh_buffer_pack(payload, + "sd", + orig_addr, + orig_port); + if (rc != SSH_OK) { + ssh_set_error_oom(session); + goto error; + } pending: - rc = channel_open(channel, - "x11", - CHANNEL_INITIAL_WINDOW, - CHANNEL_MAX_PACKET, - payload); + rc = channel_open(channel, + "x11", + CHANNEL_INITIAL_WINDOW, + CHANNEL_MAX_PACKET, + payload); error: - ssh_buffer_free(payload); + ssh_buffer_free(payload); - return rc; + return rc; } /** @@ -3495,29 +3496,29 @@ error: * (including attempts to send exit status via SSH-v1 session). */ int ssh_channel_request_send_exit_status(ssh_channel channel, int exit_status) { - ssh_buffer buffer = NULL; - int rc = SSH_ERROR; - - if(channel == NULL) { - return SSH_ERROR; - } - - buffer = ssh_buffer_new(); - if (buffer == NULL) { - ssh_set_error_oom(channel->session); - goto error; - } - - rc = ssh_buffer_pack(buffer, "d", exit_status); - if (rc != SSH_OK) { - ssh_set_error_oom(channel->session); - goto error; - } - - rc = channel_request(channel, "exit-status", buffer, 0); + ssh_buffer buffer = NULL; + int rc = SSH_ERROR; + + if (channel == NULL) { + return SSH_ERROR; + } + + buffer = ssh_buffer_new(); + if (buffer == NULL) { + ssh_set_error_oom(channel->session); + goto error; + } + + rc = ssh_buffer_pack(buffer, "d", exit_status); + if (rc != SSH_OK) { + ssh_set_error_oom(channel->session); + goto error; + } + + rc = channel_request(channel, "exit-status", buffer, 0); error: - ssh_buffer_free(buffer); - return rc; + ssh_buffer_free(buffer); + return rc; } /** @@ -3541,38 +3542,38 @@ error: */ int ssh_channel_request_send_exit_signal(ssh_channel channel, const char *sig, int core, const char *errmsg, const char *lang) { - ssh_buffer buffer = NULL; - int rc = SSH_ERROR; - - if(channel == NULL) { - return rc; - } - if(sig == NULL || errmsg == NULL || lang == NULL) { - ssh_set_error_invalid(channel->session); - return rc; - } - - buffer = ssh_buffer_new(); - if (buffer == NULL) { - ssh_set_error_oom(channel->session); - goto error; - } - - rc = ssh_buffer_pack(buffer, - "sbss", - sig, - core ? 1 : 0, - errmsg, - lang); - if (rc != SSH_OK) { - ssh_set_error_oom(channel->session); - goto error; - } - - rc = channel_request(channel, "exit-signal", buffer, 0); + ssh_buffer buffer = NULL; + int rc = SSH_ERROR; + + if (channel == NULL) { + return rc; + } + if (sig == NULL || errmsg == NULL || lang == NULL) { + ssh_set_error_invalid(channel->session); + return rc; + } + + buffer = ssh_buffer_new(); + if (buffer == NULL) { + ssh_set_error_oom(channel->session); + goto error; + } + + rc = ssh_buffer_pack(buffer, + "sbss", + sig, + core ? 1 : 0, + errmsg, + lang); + if (rc != SSH_OK) { + ssh_set_error_oom(channel->session); + goto error; + } + + rc = channel_request(channel, "exit-signal", buffer, 0); error: - ssh_buffer_free(buffer); - return rc; + ssh_buffer_free(buffer); + return rc; } #endif -- 2.18.0
Archive administrator: postmaster@lists.cynapses.org